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 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
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_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
96 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"};
97 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"};
98 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"};
99 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"};
100 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"};
101 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
102 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
103 cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
104 cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"};
105 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
106 cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
107 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
108 cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
109 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)"};
110 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)"};
111 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
112 cvar_t r_cullentities_trace_expand = {0, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
113 cvar_t r_cullentities_trace_pad = {0, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
114 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
115 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"};
116 cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
117 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
118 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
120 cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps (DEPRECATED)"};
121 cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier (DEPRECATED)"};
122 #define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit))
124 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"};
125 cvar_t r_fullbright_directed_ambient = {0, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
126 cvar_t r_fullbright_directed_diffuse = {0, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
127 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"};
128 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"};
130 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
131 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
132 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
133 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."};
134 cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
135 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
136 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
137 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."};
138 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
139 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
140 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."};
141 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."};
142 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
143 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"};
144 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"};
145 cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
146 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
147 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
148 cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
149 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
150 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"};
151 cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
152 cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
153 cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
154 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
155 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
157 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
158 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
159 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
160 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
161 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
162 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
163 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
164 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
166 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)"};
167 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"};
169 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
170 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
171 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
173 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"};
174 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"};
175 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)"};
176 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"};
177 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
178 cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
179 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"};
180 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)"};
181 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)"};
182 cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
184 cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
185 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)"};
186 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
187 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)"};
188 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
189 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)"};
190 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)"};
191 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
192 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"};
193 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."};
194 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
195 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)"};
196 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)"};
197 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)"};
198 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)"};
199 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)"};
200 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)"};
201 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)"};
202 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)"};
204 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)"};
205 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)"};
206 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
207 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"};
208 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
209 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
210 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
211 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"};
212 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"};
214 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
215 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
216 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
217 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
219 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
220 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
222 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
223 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
224 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
225 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
226 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
227 cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
229 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
230 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
231 cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
232 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
233 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
234 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
235 cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
236 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
237 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
238 cvar_t r_hdr_irisadaptation_radius = {CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
240 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"};
242 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"};
244 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
246 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
248 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)"};
249 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)"};
250 cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
251 cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
253 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
254 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"};
256 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."};
258 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)"};
259 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
261 {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
262 {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
263 {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
264 {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
267 extern cvar_t v_glslgamma_2d;
269 extern qboolean v_flipped_state;
271 r_framebufferstate_t r_fb;
273 /// shadow volume bsp struct with automatically growing nodes buffer
276 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
278 rtexture_t *r_texture_blanknormalmap;
279 rtexture_t *r_texture_white;
280 rtexture_t *r_texture_grey128;
281 rtexture_t *r_texture_black;
282 rtexture_t *r_texture_notexture;
283 rtexture_t *r_texture_whitecube;
284 rtexture_t *r_texture_normalizationcube;
285 rtexture_t *r_texture_fogattenuation;
286 rtexture_t *r_texture_fogheighttexture;
287 rtexture_t *r_texture_gammaramps;
288 unsigned int r_texture_gammaramps_serial;
289 //rtexture_t *r_texture_fogintensity;
290 rtexture_t *r_texture_reflectcube;
292 // TODO: hash lookups?
293 typedef struct cubemapinfo_s
300 int r_texture_numcubemaps;
301 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
303 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
304 unsigned int r_numqueries;
305 unsigned int r_maxqueries;
307 typedef struct r_qwskincache_s
309 char name[MAX_QPATH];
310 skinframe_t *skinframe;
314 static r_qwskincache_t *r_qwskincache;
315 static int r_qwskincache_size;
317 /// vertex coordinates for a quad that covers the screen exactly
318 extern const float r_screenvertex3f[12];
319 const float r_screenvertex3f[12] =
327 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
330 for (i = 0;i < verts;i++)
341 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
344 for (i = 0;i < verts;i++)
354 // FIXME: move this to client?
357 if (gamemode == GAME_NEHAHRA)
359 Cvar_Set("gl_fogenable", "0");
360 Cvar_Set("gl_fogdensity", "0.2");
361 Cvar_Set("gl_fogred", "0.3");
362 Cvar_Set("gl_foggreen", "0.3");
363 Cvar_Set("gl_fogblue", "0.3");
365 r_refdef.fog_density = 0;
366 r_refdef.fog_red = 0;
367 r_refdef.fog_green = 0;
368 r_refdef.fog_blue = 0;
369 r_refdef.fog_alpha = 1;
370 r_refdef.fog_start = 0;
371 r_refdef.fog_end = 16384;
372 r_refdef.fog_height = 1<<30;
373 r_refdef.fog_fadedepth = 128;
374 memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
377 static void R_BuildBlankTextures(void)
379 unsigned char data[4];
380 data[2] = 128; // normal X
381 data[1] = 128; // normal Y
382 data[0] = 255; // normal Z
383 data[3] = 255; // height
384 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
389 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
394 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
399 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
402 static void R_BuildNoTexture(void)
405 unsigned char pix[16][16][4];
406 // this makes a light grey/dark grey checkerboard texture
407 for (y = 0;y < 16;y++)
409 for (x = 0;x < 16;x++)
411 if ((y < 8) ^ (x < 8))
427 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
430 static void R_BuildWhiteCube(void)
432 unsigned char data[6*1*1*4];
433 memset(data, 255, sizeof(data));
434 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
437 static void R_BuildNormalizationCube(void)
441 vec_t s, t, intensity;
444 data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
445 for (side = 0;side < 6;side++)
447 for (y = 0;y < NORMSIZE;y++)
449 for (x = 0;x < NORMSIZE;x++)
451 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
452 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
487 intensity = 127.0f / sqrt(DotProduct(v, v));
488 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
489 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
490 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
491 data[((side*64+y)*64+x)*4+3] = 255;
495 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
499 static void R_BuildFogTexture(void)
503 unsigned char data1[FOGWIDTH][4];
504 //unsigned char data2[FOGWIDTH][4];
507 r_refdef.fogmasktable_start = r_refdef.fog_start;
508 r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
509 r_refdef.fogmasktable_range = r_refdef.fogrange;
510 r_refdef.fogmasktable_density = r_refdef.fog_density;
512 r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
513 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
515 d = (x * r - r_refdef.fogmasktable_start);
516 if(developer_extra.integer)
517 Con_DPrintf("%f ", d);
519 if (r_fog_exp2.integer)
520 alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
522 alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
523 if(developer_extra.integer)
524 Con_DPrintf(" : %f ", alpha);
525 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
526 if(developer_extra.integer)
527 Con_DPrintf(" = %f\n", alpha);
528 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
531 for (x = 0;x < FOGWIDTH;x++)
533 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
538 //data2[x][0] = 255 - b;
539 //data2[x][1] = 255 - b;
540 //data2[x][2] = 255 - b;
543 if (r_texture_fogattenuation)
545 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
546 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
550 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
551 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
555 static void R_BuildFogHeightTexture(void)
557 unsigned char *inpixels;
565 strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
566 if (r_refdef.fogheighttexturename[0])
567 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
570 r_refdef.fog_height_tablesize = 0;
571 if (r_texture_fogheighttexture)
572 R_FreeTexture(r_texture_fogheighttexture);
573 r_texture_fogheighttexture = NULL;
574 if (r_refdef.fog_height_table2d)
575 Mem_Free(r_refdef.fog_height_table2d);
576 r_refdef.fog_height_table2d = NULL;
577 if (r_refdef.fog_height_table1d)
578 Mem_Free(r_refdef.fog_height_table1d);
579 r_refdef.fog_height_table1d = NULL;
583 r_refdef.fog_height_tablesize = size;
584 r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
585 r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
586 memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
588 // LordHavoc: now the magic - what is that table2d for? it is a cooked
589 // average fog color table accounting for every fog layer between a point
590 // and the camera. (Note: attenuation is handled separately!)
591 for (y = 0;y < size;y++)
593 for (x = 0;x < size;x++)
599 for (j = x;j <= y;j++)
601 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
607 for (j = x;j >= y;j--)
609 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
614 r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
615 r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
616 r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
617 r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
620 r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
623 //=======================================================================================================================================================
625 static const char *builtinshaderstrings[] =
627 #include "shader_glsl.h"
631 //=======================================================================================================================================================
633 typedef struct shaderpermutationinfo_s
638 shaderpermutationinfo_t;
640 typedef struct shadermodeinfo_s
642 const char *sourcebasename;
643 const char *extension;
644 const char **builtinshaderstrings;
653 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
654 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
656 {"#define USEDIFFUSE\n", " diffuse"},
657 {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
658 {"#define USEVIEWTINT\n", " viewtint"},
659 {"#define USECOLORMAPPING\n", " colormapping"},
660 {"#define USESATURATION\n", " saturation"},
661 {"#define USEFOGINSIDE\n", " foginside"},
662 {"#define USEFOGOUTSIDE\n", " fogoutside"},
663 {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
664 {"#define USEFOGALPHAHACK\n", " fogalphahack"},
665 {"#define USEGAMMARAMPS\n", " gammaramps"},
666 {"#define USECUBEFILTER\n", " cubefilter"},
667 {"#define USEGLOW\n", " glow"},
668 {"#define USEBLOOM\n", " bloom"},
669 {"#define USESPECULAR\n", " specular"},
670 {"#define USEPOSTPROCESSING\n", " postprocessing"},
671 {"#define USEREFLECTION\n", " reflection"},
672 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
673 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
674 {"#define USESHADOWMAP2D\n", " shadowmap2d"},
675 {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
676 {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
677 {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
678 {"#define USEALPHAKILL\n", " alphakill"},
679 {"#define USEREFLECTCUBE\n", " reflectcube"},
680 {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
681 {"#define USEBOUNCEGRID\n", " bouncegrid"},
682 {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
683 {"#define USETRIPPY\n", " trippy"},
684 {"#define USEDEPTHRGB\n", " depthrgb"},
685 {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
686 {"#define USESKELETAL\n", " skeletal"},
687 {"#define USEOCCLUDE\n", " occlude"}
690 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
691 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
693 // SHADERLANGUAGE_GLSL
695 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
696 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
697 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
698 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
699 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
700 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
701 {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
702 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
703 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
704 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
705 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
706 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
707 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
708 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
709 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
710 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
711 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
715 struct r_glsl_permutation_s;
716 typedef struct r_glsl_permutation_s
719 struct r_glsl_permutation_s *hashnext;
721 dpuint64 permutation;
723 /// indicates if we have tried compiling this permutation already
725 /// 0 if compilation failed
727 // texture units assigned to each detected uniform
728 int tex_Texture_First;
729 int tex_Texture_Second;
730 int tex_Texture_GammaRamps;
731 int tex_Texture_Normal;
732 int tex_Texture_Color;
733 int tex_Texture_Gloss;
734 int tex_Texture_Glow;
735 int tex_Texture_SecondaryNormal;
736 int tex_Texture_SecondaryColor;
737 int tex_Texture_SecondaryGloss;
738 int tex_Texture_SecondaryGlow;
739 int tex_Texture_Pants;
740 int tex_Texture_Shirt;
741 int tex_Texture_FogHeightTexture;
742 int tex_Texture_FogMask;
743 int tex_Texture_Lightmap;
744 int tex_Texture_Deluxemap;
745 int tex_Texture_Attenuation;
746 int tex_Texture_Cube;
747 int tex_Texture_Refraction;
748 int tex_Texture_Reflection;
749 int tex_Texture_ShadowMap2D;
750 int tex_Texture_CubeProjection;
751 int tex_Texture_ScreenNormalMap;
752 int tex_Texture_ScreenDiffuse;
753 int tex_Texture_ScreenSpecular;
754 int tex_Texture_ReflectMask;
755 int tex_Texture_ReflectCube;
756 int tex_Texture_BounceGrid;
757 /// locations of detected uniforms in program object, or -1 if not found
758 int loc_Texture_First;
759 int loc_Texture_Second;
760 int loc_Texture_GammaRamps;
761 int loc_Texture_Normal;
762 int loc_Texture_Color;
763 int loc_Texture_Gloss;
764 int loc_Texture_Glow;
765 int loc_Texture_SecondaryNormal;
766 int loc_Texture_SecondaryColor;
767 int loc_Texture_SecondaryGloss;
768 int loc_Texture_SecondaryGlow;
769 int loc_Texture_Pants;
770 int loc_Texture_Shirt;
771 int loc_Texture_FogHeightTexture;
772 int loc_Texture_FogMask;
773 int loc_Texture_Lightmap;
774 int loc_Texture_Deluxemap;
775 int loc_Texture_Attenuation;
776 int loc_Texture_Cube;
777 int loc_Texture_Refraction;
778 int loc_Texture_Reflection;
779 int loc_Texture_ShadowMap2D;
780 int loc_Texture_CubeProjection;
781 int loc_Texture_ScreenNormalMap;
782 int loc_Texture_ScreenDiffuse;
783 int loc_Texture_ScreenSpecular;
784 int loc_Texture_ReflectMask;
785 int loc_Texture_ReflectCube;
786 int loc_Texture_BounceGrid;
788 int loc_BloomBlur_Parameters;
790 int loc_Color_Ambient;
791 int loc_Color_Diffuse;
792 int loc_Color_Specular;
796 int loc_DeferredColor_Ambient;
797 int loc_DeferredColor_Diffuse;
798 int loc_DeferredColor_Specular;
799 int loc_DeferredMod_Diffuse;
800 int loc_DeferredMod_Specular;
801 int loc_DistortScaleRefractReflect;
804 int loc_FogHeightFade;
806 int loc_FogPlaneViewDist;
807 int loc_FogRangeRecip;
810 int loc_LightPosition;
811 int loc_OffsetMapping_ScaleSteps;
812 int loc_OffsetMapping_LodDistance;
813 int loc_OffsetMapping_Bias;
815 int loc_ReflectColor;
816 int loc_ReflectFactor;
817 int loc_ReflectOffset;
818 int loc_RefractColor;
820 int loc_ScreenCenterRefractReflect;
821 int loc_ScreenScaleRefractReflect;
822 int loc_ScreenToDepth;
823 int loc_ShadowMap_Parameters;
824 int loc_ShadowMap_TextureScale;
825 int loc_SpecularPower;
826 int loc_Skeletal_Transform12;
831 int loc_ViewTintColor;
833 int loc_ModelToLight;
835 int loc_BackgroundTexMatrix;
836 int loc_ModelViewProjectionMatrix;
837 int loc_ModelViewMatrix;
838 int loc_PixelToScreenTexCoord;
839 int loc_ModelToReflectCube;
840 int loc_ShadowMapMatrix;
841 int loc_BloomColorSubtract;
842 int loc_NormalmapScrollBlend;
843 int loc_BounceGridMatrix;
844 int loc_BounceGridIntensity;
845 /// uniform block bindings
846 int ubibind_Skeletal_Transform12_UniformBlock;
847 /// uniform block indices
848 int ubiloc_Skeletal_Transform12_UniformBlock;
850 r_glsl_permutation_t;
852 #define SHADERPERMUTATION_HASHSIZE 256
855 // non-degradable "lightweight" shader parameters to keep the permutations simpler
856 // these can NOT degrade! only use for simple stuff
859 SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
860 SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
861 SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
862 SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
863 SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
864 SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled
865 SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
866 SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping
867 SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
868 SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
869 SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
870 SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
871 SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
872 SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
874 #define SHADERSTATICPARMS_COUNT 14
876 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
877 static int shaderstaticparms_count = 0;
879 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
880 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
882 extern qboolean r_shadow_shadowmapsampler;
883 extern int r_shadow_shadowmappcf;
884 qboolean R_CompileShader_CheckStaticParms(void)
886 static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
887 memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
888 memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
891 if (r_glsl_saturation_redcompensate.integer)
892 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
893 if (r_glsl_vertextextureblend_usebothalphas.integer)
894 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
895 if (r_shadow_glossexact.integer)
896 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
897 if (r_glsl_postprocess.integer)
899 if (r_glsl_postprocess_uservec1_enable.integer)
900 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
901 if (r_glsl_postprocess_uservec2_enable.integer)
902 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
903 if (r_glsl_postprocess_uservec3_enable.integer)
904 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
905 if (r_glsl_postprocess_uservec4_enable.integer)
906 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
909 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
910 if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
911 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
913 if (r_shadow_shadowmapsampler)
914 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
915 if (r_shadow_shadowmappcf > 1)
916 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
917 else if (r_shadow_shadowmappcf)
918 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
919 if (r_celshading.integer)
920 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
921 if (r_celoutlines.integer)
922 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
924 return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
927 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
928 if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
929 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
931 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
932 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
934 shaderstaticparms_count = 0;
937 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
938 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
939 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
940 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
941 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
942 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
943 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
944 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
945 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
946 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
947 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
948 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
949 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
950 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
953 /// information about each possible shader permutation
954 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
955 /// currently selected permutation
956 r_glsl_permutation_t *r_glsl_permutation;
957 /// storage for permutations linked in the hash table
958 memexpandablearray_t r_glsl_permutationarray;
960 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
962 //unsigned int hashdepth = 0;
963 unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
964 r_glsl_permutation_t *p;
965 for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
967 if (p->mode == mode && p->permutation == permutation)
969 //if (hashdepth > 10)
970 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
975 p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
977 p->permutation = permutation;
978 p->hashnext = r_glsl_permutationhash[mode][hashindex];
979 r_glsl_permutationhash[mode][hashindex] = p;
980 //if (hashdepth > 10)
981 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
985 static char *R_ShaderStrCat(const char **strings)
988 const char **p = strings;
991 for (p = strings;(t = *p);p++)
994 s = string = (char *)Mem_Alloc(r_main_mempool, len);
996 for (p = strings;(t = *p);p++)
1006 static char *R_ShaderStrCat(const char **strings);
1007 static void R_InitShaderModeInfo(void)
1010 shadermodeinfo_t *modeinfo;
1011 // 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)
1012 for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1014 for (i = 0; i < SHADERMODE_COUNT; i++)
1016 char filename[MAX_QPATH];
1017 modeinfo = &shadermodeinfo[language][i];
1018 modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1019 modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1020 dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1021 modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1026 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1029 // if the mode has no filename we have to return the builtin string
1030 if (builtinonly || !modeinfo->filename)
1031 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1032 // note that FS_LoadFile appends a 0 byte to make it a valid string
1033 shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1036 if (printfromdisknotice)
1037 Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1038 return shaderstring;
1040 // fall back to builtinstring
1041 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1044 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1049 shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1051 char permutationname[256];
1052 int vertstrings_count = 0;
1053 int geomstrings_count = 0;
1054 int fragstrings_count = 0;
1055 const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1056 const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1057 const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1064 permutationname[0] = 0;
1065 sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1067 strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1069 // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1070 if(vid.support.glshaderversion >= 140)
1072 vertstrings_list[vertstrings_count++] = "#version 140\n";
1073 geomstrings_list[geomstrings_count++] = "#version 140\n";
1074 fragstrings_list[fragstrings_count++] = "#version 140\n";
1075 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1076 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1077 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1079 // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1080 else if(vid.support.glshaderversion >= 130)
1082 vertstrings_list[vertstrings_count++] = "#version 130\n";
1083 geomstrings_list[geomstrings_count++] = "#version 130\n";
1084 fragstrings_list[fragstrings_count++] = "#version 130\n";
1085 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1086 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1087 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1089 // if we can do #version 120, we should (this adds the invariant keyword)
1090 else if(vid.support.glshaderversion >= 120)
1092 vertstrings_list[vertstrings_count++] = "#version 120\n";
1093 geomstrings_list[geomstrings_count++] = "#version 120\n";
1094 fragstrings_list[fragstrings_count++] = "#version 120\n";
1095 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1096 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1097 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1099 // GLES also adds several things from GLSL120
1100 switch(vid.renderpath)
1102 case RENDERPATH_GLES2:
1103 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1104 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1105 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1111 // the first pretext is which type of shader to compile as
1112 // (later these will all be bound together as a program object)
1113 vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1114 geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1115 fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1117 // the second pretext is the mode (for example a light source)
1118 vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1119 geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1120 fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1121 strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1123 // now add all the permutation pretexts
1124 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1126 if (permutation & (1ll<<i))
1128 vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1129 geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1130 fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1131 strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1135 // keep line numbers correct
1136 vertstrings_list[vertstrings_count++] = "\n";
1137 geomstrings_list[geomstrings_count++] = "\n";
1138 fragstrings_list[fragstrings_count++] = "\n";
1143 R_CompileShader_AddStaticParms(mode, permutation);
1144 memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1145 vertstrings_count += shaderstaticparms_count;
1146 memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1147 geomstrings_count += shaderstaticparms_count;
1148 memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1149 fragstrings_count += shaderstaticparms_count;
1151 // now append the shader text itself
1152 vertstrings_list[vertstrings_count++] = sourcestring;
1153 geomstrings_list[geomstrings_count++] = sourcestring;
1154 fragstrings_list[fragstrings_count++] = sourcestring;
1156 // we don't currently use geometry shaders for anything, so just empty the list
1157 geomstrings_count = 0;
1159 // compile the shader program
1160 if (vertstrings_count + geomstrings_count + fragstrings_count)
1161 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1165 qglUseProgram(p->program);CHECKGLERROR
1166 // look up all the uniform variable names we care about, so we don't
1167 // have to look them up every time we set them
1172 GLint activeuniformindex = 0;
1173 GLint numactiveuniforms = 0;
1174 char uniformname[128];
1175 GLsizei uniformnamelength = 0;
1176 GLint uniformsize = 0;
1177 GLenum uniformtype = 0;
1178 memset(uniformname, 0, sizeof(uniformname));
1179 qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1180 Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1181 for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1183 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1184 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1189 p->loc_Texture_First = qglGetUniformLocation(p->program, "Texture_First");
1190 p->loc_Texture_Second = qglGetUniformLocation(p->program, "Texture_Second");
1191 p->loc_Texture_GammaRamps = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1192 p->loc_Texture_Normal = qglGetUniformLocation(p->program, "Texture_Normal");
1193 p->loc_Texture_Color = qglGetUniformLocation(p->program, "Texture_Color");
1194 p->loc_Texture_Gloss = qglGetUniformLocation(p->program, "Texture_Gloss");
1195 p->loc_Texture_Glow = qglGetUniformLocation(p->program, "Texture_Glow");
1196 p->loc_Texture_SecondaryNormal = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1197 p->loc_Texture_SecondaryColor = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1198 p->loc_Texture_SecondaryGloss = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1199 p->loc_Texture_SecondaryGlow = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1200 p->loc_Texture_Pants = qglGetUniformLocation(p->program, "Texture_Pants");
1201 p->loc_Texture_Shirt = qglGetUniformLocation(p->program, "Texture_Shirt");
1202 p->loc_Texture_FogHeightTexture = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1203 p->loc_Texture_FogMask = qglGetUniformLocation(p->program, "Texture_FogMask");
1204 p->loc_Texture_Lightmap = qglGetUniformLocation(p->program, "Texture_Lightmap");
1205 p->loc_Texture_Deluxemap = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1206 p->loc_Texture_Attenuation = qglGetUniformLocation(p->program, "Texture_Attenuation");
1207 p->loc_Texture_Cube = qglGetUniformLocation(p->program, "Texture_Cube");
1208 p->loc_Texture_Refraction = qglGetUniformLocation(p->program, "Texture_Refraction");
1209 p->loc_Texture_Reflection = qglGetUniformLocation(p->program, "Texture_Reflection");
1210 p->loc_Texture_ShadowMap2D = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1211 p->loc_Texture_CubeProjection = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1212 p->loc_Texture_ScreenNormalMap = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1213 p->loc_Texture_ScreenDiffuse = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1214 p->loc_Texture_ScreenSpecular = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1215 p->loc_Texture_ReflectMask = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1216 p->loc_Texture_ReflectCube = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1217 p->loc_Texture_BounceGrid = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1218 p->loc_Alpha = qglGetUniformLocation(p->program, "Alpha");
1219 p->loc_BloomBlur_Parameters = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1220 p->loc_ClientTime = qglGetUniformLocation(p->program, "ClientTime");
1221 p->loc_Color_Ambient = qglGetUniformLocation(p->program, "Color_Ambient");
1222 p->loc_Color_Diffuse = qglGetUniformLocation(p->program, "Color_Diffuse");
1223 p->loc_Color_Specular = qglGetUniformLocation(p->program, "Color_Specular");
1224 p->loc_Color_Glow = qglGetUniformLocation(p->program, "Color_Glow");
1225 p->loc_Color_Pants = qglGetUniformLocation(p->program, "Color_Pants");
1226 p->loc_Color_Shirt = qglGetUniformLocation(p->program, "Color_Shirt");
1227 p->loc_DeferredColor_Ambient = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1228 p->loc_DeferredColor_Diffuse = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1229 p->loc_DeferredColor_Specular = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1230 p->loc_DeferredMod_Diffuse = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1231 p->loc_DeferredMod_Specular = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1232 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1233 p->loc_EyePosition = qglGetUniformLocation(p->program, "EyePosition");
1234 p->loc_FogColor = qglGetUniformLocation(p->program, "FogColor");
1235 p->loc_FogHeightFade = qglGetUniformLocation(p->program, "FogHeightFade");
1236 p->loc_FogPlane = qglGetUniformLocation(p->program, "FogPlane");
1237 p->loc_FogPlaneViewDist = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1238 p->loc_FogRangeRecip = qglGetUniformLocation(p->program, "FogRangeRecip");
1239 p->loc_LightColor = qglGetUniformLocation(p->program, "LightColor");
1240 p->loc_LightDir = qglGetUniformLocation(p->program, "LightDir");
1241 p->loc_LightPosition = qglGetUniformLocation(p->program, "LightPosition");
1242 p->loc_OffsetMapping_ScaleSteps = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1243 p->loc_OffsetMapping_LodDistance = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1244 p->loc_OffsetMapping_Bias = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1245 p->loc_PixelSize = qglGetUniformLocation(p->program, "PixelSize");
1246 p->loc_ReflectColor = qglGetUniformLocation(p->program, "ReflectColor");
1247 p->loc_ReflectFactor = qglGetUniformLocation(p->program, "ReflectFactor");
1248 p->loc_ReflectOffset = qglGetUniformLocation(p->program, "ReflectOffset");
1249 p->loc_RefractColor = qglGetUniformLocation(p->program, "RefractColor");
1250 p->loc_Saturation = qglGetUniformLocation(p->program, "Saturation");
1251 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1252 p->loc_ScreenScaleRefractReflect = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1253 p->loc_ScreenToDepth = qglGetUniformLocation(p->program, "ScreenToDepth");
1254 p->loc_ShadowMap_Parameters = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1255 p->loc_ShadowMap_TextureScale = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1256 p->loc_SpecularPower = qglGetUniformLocation(p->program, "SpecularPower");
1257 p->loc_UserVec1 = qglGetUniformLocation(p->program, "UserVec1");
1258 p->loc_UserVec2 = qglGetUniformLocation(p->program, "UserVec2");
1259 p->loc_UserVec3 = qglGetUniformLocation(p->program, "UserVec3");
1260 p->loc_UserVec4 = qglGetUniformLocation(p->program, "UserVec4");
1261 p->loc_ViewTintColor = qglGetUniformLocation(p->program, "ViewTintColor");
1262 p->loc_ViewToLight = qglGetUniformLocation(p->program, "ViewToLight");
1263 p->loc_ModelToLight = qglGetUniformLocation(p->program, "ModelToLight");
1264 p->loc_TexMatrix = qglGetUniformLocation(p->program, "TexMatrix");
1265 p->loc_BackgroundTexMatrix = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1266 p->loc_ModelViewMatrix = qglGetUniformLocation(p->program, "ModelViewMatrix");
1267 p->loc_ModelViewProjectionMatrix = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1268 p->loc_PixelToScreenTexCoord = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1269 p->loc_ModelToReflectCube = qglGetUniformLocation(p->program, "ModelToReflectCube");
1270 p->loc_ShadowMapMatrix = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1271 p->loc_BloomColorSubtract = qglGetUniformLocation(p->program, "BloomColorSubtract");
1272 p->loc_NormalmapScrollBlend = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1273 p->loc_BounceGridMatrix = qglGetUniformLocation(p->program, "BounceGridMatrix");
1274 p->loc_BounceGridIntensity = qglGetUniformLocation(p->program, "BounceGridIntensity");
1275 // initialize the samplers to refer to the texture units we use
1276 p->tex_Texture_First = -1;
1277 p->tex_Texture_Second = -1;
1278 p->tex_Texture_GammaRamps = -1;
1279 p->tex_Texture_Normal = -1;
1280 p->tex_Texture_Color = -1;
1281 p->tex_Texture_Gloss = -1;
1282 p->tex_Texture_Glow = -1;
1283 p->tex_Texture_SecondaryNormal = -1;
1284 p->tex_Texture_SecondaryColor = -1;
1285 p->tex_Texture_SecondaryGloss = -1;
1286 p->tex_Texture_SecondaryGlow = -1;
1287 p->tex_Texture_Pants = -1;
1288 p->tex_Texture_Shirt = -1;
1289 p->tex_Texture_FogHeightTexture = -1;
1290 p->tex_Texture_FogMask = -1;
1291 p->tex_Texture_Lightmap = -1;
1292 p->tex_Texture_Deluxemap = -1;
1293 p->tex_Texture_Attenuation = -1;
1294 p->tex_Texture_Cube = -1;
1295 p->tex_Texture_Refraction = -1;
1296 p->tex_Texture_Reflection = -1;
1297 p->tex_Texture_ShadowMap2D = -1;
1298 p->tex_Texture_CubeProjection = -1;
1299 p->tex_Texture_ScreenNormalMap = -1;
1300 p->tex_Texture_ScreenDiffuse = -1;
1301 p->tex_Texture_ScreenSpecular = -1;
1302 p->tex_Texture_ReflectMask = -1;
1303 p->tex_Texture_ReflectCube = -1;
1304 p->tex_Texture_BounceGrid = -1;
1305 // bind the texture samplers in use
1307 if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;}
1308 if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;}
1309 if (p->loc_Texture_GammaRamps >= 0) {p->tex_Texture_GammaRamps = sampler;qglUniform1i(p->loc_Texture_GammaRamps , sampler);sampler++;}
1310 if (p->loc_Texture_Normal >= 0) {p->tex_Texture_Normal = sampler;qglUniform1i(p->loc_Texture_Normal , sampler);sampler++;}
1311 if (p->loc_Texture_Color >= 0) {p->tex_Texture_Color = sampler;qglUniform1i(p->loc_Texture_Color , sampler);sampler++;}
1312 if (p->loc_Texture_Gloss >= 0) {p->tex_Texture_Gloss = sampler;qglUniform1i(p->loc_Texture_Gloss , sampler);sampler++;}
1313 if (p->loc_Texture_Glow >= 0) {p->tex_Texture_Glow = sampler;qglUniform1i(p->loc_Texture_Glow , sampler);sampler++;}
1314 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1315 if (p->loc_Texture_SecondaryColor >= 0) {p->tex_Texture_SecondaryColor = sampler;qglUniform1i(p->loc_Texture_SecondaryColor , sampler);sampler++;}
1316 if (p->loc_Texture_SecondaryGloss >= 0) {p->tex_Texture_SecondaryGloss = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss , sampler);sampler++;}
1317 if (p->loc_Texture_SecondaryGlow >= 0) {p->tex_Texture_SecondaryGlow = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow , sampler);sampler++;}
1318 if (p->loc_Texture_Pants >= 0) {p->tex_Texture_Pants = sampler;qglUniform1i(p->loc_Texture_Pants , sampler);sampler++;}
1319 if (p->loc_Texture_Shirt >= 0) {p->tex_Texture_Shirt = sampler;qglUniform1i(p->loc_Texture_Shirt , sampler);sampler++;}
1320 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1321 if (p->loc_Texture_FogMask >= 0) {p->tex_Texture_FogMask = sampler;qglUniform1i(p->loc_Texture_FogMask , sampler);sampler++;}
1322 if (p->loc_Texture_Lightmap >= 0) {p->tex_Texture_Lightmap = sampler;qglUniform1i(p->loc_Texture_Lightmap , sampler);sampler++;}
1323 if (p->loc_Texture_Deluxemap >= 0) {p->tex_Texture_Deluxemap = sampler;qglUniform1i(p->loc_Texture_Deluxemap , sampler);sampler++;}
1324 if (p->loc_Texture_Attenuation >= 0) {p->tex_Texture_Attenuation = sampler;qglUniform1i(p->loc_Texture_Attenuation , sampler);sampler++;}
1325 if (p->loc_Texture_Cube >= 0) {p->tex_Texture_Cube = sampler;qglUniform1i(p->loc_Texture_Cube , sampler);sampler++;}
1326 if (p->loc_Texture_Refraction >= 0) {p->tex_Texture_Refraction = sampler;qglUniform1i(p->loc_Texture_Refraction , sampler);sampler++;}
1327 if (p->loc_Texture_Reflection >= 0) {p->tex_Texture_Reflection = sampler;qglUniform1i(p->loc_Texture_Reflection , sampler);sampler++;}
1328 if (p->loc_Texture_ShadowMap2D >= 0) {p->tex_Texture_ShadowMap2D = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D , sampler);sampler++;}
1329 if (p->loc_Texture_CubeProjection >= 0) {p->tex_Texture_CubeProjection = sampler;qglUniform1i(p->loc_Texture_CubeProjection , sampler);sampler++;}
1330 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1331 if (p->loc_Texture_ScreenDiffuse >= 0) {p->tex_Texture_ScreenDiffuse = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse , sampler);sampler++;}
1332 if (p->loc_Texture_ScreenSpecular >= 0) {p->tex_Texture_ScreenSpecular = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular , sampler);sampler++;}
1333 if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;}
1334 if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;}
1335 if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;}
1336 // get the uniform block indices so we can bind them
1337 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1338 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1339 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
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 %llx\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_GL32:
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 *t, 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;
1482 if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1483 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1484 if (suppresstexalpha)
1485 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1486 if (vid.allowalphatocoverage)
1487 GL_AlphaToCoverage(false);
1488 switch (vid.renderpath)
1490 case RENDERPATH_GL32:
1491 case RENDERPATH_GLES2:
1492 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1493 if (r_glsl_permutation->tex_Texture_First >= 0)
1494 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1495 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1496 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1501 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1503 R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1506 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1508 dpuint64 permutation = 0;
1509 if (r_trippy.integer && !notrippy)
1510 permutation |= SHADERPERMUTATION_TRIPPY;
1512 permutation |= SHADERPERMUTATION_DEPTHRGB;
1514 permutation |= SHADERPERMUTATION_SKELETAL;
1516 if (vid.allowalphatocoverage)
1517 GL_AlphaToCoverage(false);
1518 switch (vid.renderpath)
1520 case RENDERPATH_GL32:
1521 case RENDERPATH_GLES2:
1522 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1523 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1524 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);
1530 #define BLENDFUNC_ALLOWS_COLORMOD 1
1531 #define BLENDFUNC_ALLOWS_FOG 2
1532 #define BLENDFUNC_ALLOWS_FOG_HACK0 4
1533 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1534 #define BLENDFUNC_ALLOWS_ANYFOG (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1535 static int R_BlendFuncFlags(int src, int dst)
1539 // a blendfunc allows colormod if:
1540 // a) it can never keep the destination pixel invariant, or
1541 // b) it can keep the destination pixel invariant, and still can do so if colormodded
1542 // this is to prevent unintended side effects from colormod
1544 // a blendfunc allows fog if:
1545 // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1546 // this is to prevent unintended side effects from fog
1548 // these checks are the output of fogeval.pl
1550 r |= BLENDFUNC_ALLOWS_COLORMOD;
1551 if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1552 if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1553 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1554 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1555 if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556 if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557 if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1558 if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1559 if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1560 if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1561 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1562 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1563 if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1564 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1565 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1566 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1567 if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1568 if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1569 if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1570 if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1571 if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1576 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)
1578 // select a permutation of the lighting shader appropriate to this
1579 // combination of texture, entity, light source, and fogging, only use the
1580 // minimum features necessary to avoid wasting rendering time in the
1581 // fragment shader on features that are not being used
1582 dpuint64 permutation = 0;
1583 unsigned int mode = 0;
1585 texture_t *t = rsurface.texture;
1587 matrix4x4_t tempmatrix;
1588 r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1589 if (r_trippy.integer && !notrippy)
1590 permutation |= SHADERPERMUTATION_TRIPPY;
1591 if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1592 permutation |= SHADERPERMUTATION_ALPHAKILL;
1593 if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1594 permutation |= SHADERPERMUTATION_OCCLUDE;
1595 if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1596 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1597 if (rsurfacepass == RSURFPASS_BACKGROUND)
1599 // distorted background
1600 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1602 mode = SHADERMODE_WATER;
1603 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1604 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1605 if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1607 // this is the right thing to do for wateralpha
1608 GL_BlendFunc(GL_ONE, GL_ZERO);
1609 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1613 // this is the right thing to do for entity alpha
1614 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1615 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1618 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1620 mode = SHADERMODE_REFRACTION;
1621 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1622 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1623 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1624 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1628 mode = SHADERMODE_GENERIC;
1629 permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1630 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1631 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1633 if (vid.allowalphatocoverage)
1634 GL_AlphaToCoverage(false);
1636 else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1638 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1640 switch(t->offsetmapping)
1642 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1643 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1644 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1645 case OFFSETMAPPING_OFF: break;
1648 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1649 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1650 // normalmap (deferred prepass), may use alpha test on diffuse
1651 mode = SHADERMODE_DEFERREDGEOMETRY;
1652 GL_BlendFunc(GL_ONE, GL_ZERO);
1653 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1654 if (vid.allowalphatocoverage)
1655 GL_AlphaToCoverage(false);
1657 else if (rsurfacepass == RSURFPASS_RTLIGHT)
1659 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1661 switch(t->offsetmapping)
1663 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1664 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1665 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1666 case OFFSETMAPPING_OFF: break;
1669 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1670 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1671 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1672 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1674 mode = SHADERMODE_LIGHTSOURCE;
1675 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1676 permutation |= SHADERPERMUTATION_CUBEFILTER;
1677 if (VectorLength2(rtlightdiffuse) > 0)
1678 permutation |= SHADERPERMUTATION_DIFFUSE;
1679 if (VectorLength2(rtlightspecular) > 0)
1680 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1681 if (r_refdef.fogenabled)
1682 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1683 if (t->colormapping)
1684 permutation |= SHADERPERMUTATION_COLORMAPPING;
1685 if (r_shadow_usingshadowmap2d)
1687 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1688 if(r_shadow_shadowmapvsdct)
1689 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1691 if (r_shadow_shadowmap2ddepthbuffer)
1692 permutation |= SHADERPERMUTATION_DEPTHRGB;
1694 if (t->reflectmasktexture)
1695 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1696 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1697 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1698 if (vid.allowalphatocoverage)
1699 GL_AlphaToCoverage(false);
1701 else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1703 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1705 switch(t->offsetmapping)
1707 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1708 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1709 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1710 case OFFSETMAPPING_OFF: break;
1713 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1714 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1715 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1716 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1717 // directional model lighting
1718 mode = SHADERMODE_LIGHTDIRECTION;
1719 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1720 permutation |= SHADERPERMUTATION_GLOW;
1721 if (VectorLength2(t->render_modellight_diffuse))
1722 permutation |= SHADERPERMUTATION_DIFFUSE;
1723 if (VectorLength2(t->render_modellight_specular) > 0)
1724 permutation |= SHADERPERMUTATION_SPECULAR;
1725 if (r_refdef.fogenabled)
1726 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1727 if (t->colormapping)
1728 permutation |= SHADERPERMUTATION_COLORMAPPING;
1729 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1731 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1732 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1734 if (r_shadow_shadowmap2ddepthbuffer)
1735 permutation |= SHADERPERMUTATION_DEPTHRGB;
1737 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1738 permutation |= SHADERPERMUTATION_REFLECTION;
1739 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1740 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1741 if (t->reflectmasktexture)
1742 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1743 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1745 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1746 if (r_shadow_bouncegrid_state.directional)
1747 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1749 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1750 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1751 // when using alphatocoverage, we don't need alphakill
1752 if (vid.allowalphatocoverage)
1754 if (r_transparent_alphatocoverage.integer)
1756 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1757 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1760 GL_AlphaToCoverage(false);
1765 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1767 switch(t->offsetmapping)
1769 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1770 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1771 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1772 case OFFSETMAPPING_OFF: break;
1775 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1776 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1777 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1778 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1780 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1781 permutation |= SHADERPERMUTATION_GLOW;
1782 if (r_refdef.fogenabled)
1783 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1784 if (t->colormapping)
1785 permutation |= SHADERPERMUTATION_COLORMAPPING;
1786 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1788 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1789 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1791 if (r_shadow_shadowmap2ddepthbuffer)
1792 permutation |= SHADERPERMUTATION_DEPTHRGB;
1794 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1795 permutation |= SHADERPERMUTATION_REFLECTION;
1796 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1797 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1798 if (t->reflectmasktexture)
1799 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1800 if (FAKELIGHT_ENABLED)
1802 // fake lightmapping (q1bsp, q3bsp, fullbright map)
1803 mode = SHADERMODE_FAKELIGHT;
1804 permutation |= SHADERPERMUTATION_DIFFUSE;
1805 if (VectorLength2(t->render_lightmap_specular) > 0)
1806 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1808 else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1810 // deluxemapping (light direction texture)
1811 if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1812 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1814 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1815 permutation |= SHADERPERMUTATION_DIFFUSE;
1816 if (VectorLength2(t->render_lightmap_specular) > 0)
1817 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1819 else if (r_glsl_deluxemapping.integer >= 2)
1821 // fake deluxemapping (uniform light direction in tangentspace)
1822 if (rsurface.uselightmaptexture)
1823 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1825 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1826 permutation |= SHADERPERMUTATION_DIFFUSE;
1827 if (VectorLength2(t->render_lightmap_specular) > 0)
1828 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1830 else if (rsurface.uselightmaptexture)
1832 // ordinary lightmapping (q1bsp, q3bsp)
1833 mode = SHADERMODE_LIGHTMAP;
1837 // ordinary vertex coloring (q3bsp)
1838 mode = SHADERMODE_VERTEXCOLOR;
1840 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1842 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1843 if (r_shadow_bouncegrid_state.directional)
1844 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1846 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1847 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1848 // when using alphatocoverage, we don't need alphakill
1849 if (vid.allowalphatocoverage)
1851 if (r_transparent_alphatocoverage.integer)
1853 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1854 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1857 GL_AlphaToCoverage(false);
1860 if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1861 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1862 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1863 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1864 switch(vid.renderpath)
1866 case RENDERPATH_GL32:
1867 case RENDERPATH_GLES2:
1868 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);
1869 RSurf_UploadBuffersForBatch();
1870 // this has to be after RSurf_PrepareVerticesForBatch
1871 if (rsurface.batchskeletaltransform3x4buffer)
1872 permutation |= SHADERPERMUTATION_SKELETAL;
1873 R_SetupShader_SetPermutationGLSL(mode, permutation);
1874 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1875 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);
1877 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1878 if (mode == SHADERMODE_LIGHTSOURCE)
1880 if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1881 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1882 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1883 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1884 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1885 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1887 // additive passes are only darkened by fog, not tinted
1888 if (r_glsl_permutation->loc_FogColor >= 0)
1889 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1890 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);
1894 if (mode == SHADERMODE_FLATCOLOR)
1896 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]);
1898 else if (mode == SHADERMODE_LIGHTDIRECTION)
1900 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]);
1901 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]);
1902 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]);
1903 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]);
1904 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]);
1905 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1906 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]);
1910 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]);
1911 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]);
1912 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]);
1913 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]);
1914 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]);
1916 // additive passes are only darkened by fog, not tinted
1917 if (r_glsl_permutation->loc_FogColor >= 0)
1919 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1920 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1922 qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1924 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);
1925 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]);
1926 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]);
1927 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);
1928 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);
1929 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1930 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1931 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);
1932 if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1934 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1935 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1936 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1937 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1939 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]);
1940 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]);
1944 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]);
1945 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]);
1948 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]);
1949 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));
1950 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1951 if (r_glsl_permutation->loc_Color_Pants >= 0)
1953 if (t->pantstexture)
1954 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1956 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1958 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1960 if (t->shirttexture)
1961 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1963 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1965 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]);
1966 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1967 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1968 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1969 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1970 r_glsl_offsetmapping_scale.value*t->offsetscale,
1971 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1972 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1973 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1975 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);
1976 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1977 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]);
1978 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1979 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);}
1980 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1982 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_texture_white );
1983 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_texture_white );
1984 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps , r_texture_gammaramps );
1985 if (r_glsl_permutation->tex_Texture_Normal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal , t->nmaptexture );
1986 if (r_glsl_permutation->tex_Texture_Color >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color , t->basetexture );
1987 if (r_glsl_permutation->tex_Texture_Gloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss , t->glosstexture );
1988 if (r_glsl_permutation->tex_Texture_Glow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow , t->glowtexture );
1989 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal , t->backgroundnmaptexture );
1990 if (r_glsl_permutation->tex_Texture_SecondaryColor >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor , t->backgroundbasetexture );
1991 if (r_glsl_permutation->tex_Texture_SecondaryGloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss , t->backgroundglosstexture );
1992 if (r_glsl_permutation->tex_Texture_SecondaryGlow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow , t->backgroundglowtexture );
1993 if (r_glsl_permutation->tex_Texture_Pants >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants , t->pantstexture );
1994 if (r_glsl_permutation->tex_Texture_Shirt >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt , t->shirttexture );
1995 if (r_glsl_permutation->tex_Texture_ReflectMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask , t->reflectmasktexture );
1996 if (r_glsl_permutation->tex_Texture_ReflectCube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
1997 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture );
1998 if (r_glsl_permutation->tex_Texture_FogMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask , r_texture_fogattenuation );
1999 if (r_glsl_permutation->tex_Texture_Lightmap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2000 if (r_glsl_permutation->tex_Texture_Deluxemap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2001 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2002 if (rsurfacepass == RSURFPASS_BACKGROUND)
2004 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);
2005 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);
2006 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);
2010 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);
2012 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2013 if (r_glsl_permutation->tex_Texture_ScreenDiffuse >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse , r_shadow_prepasslightingdiffusetexture );
2014 if (r_glsl_permutation->tex_Texture_ScreenSpecular >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture );
2015 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2017 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture );
2018 if (rsurface.rtlight)
2020 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2021 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2024 if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2030 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2032 // select a permutation of the lighting shader appropriate to this
2033 // combination of texture, entity, light source, and fogging, only use the
2034 // minimum features necessary to avoid wasting rendering time in the
2035 // fragment shader on features that are not being used
2036 dpuint64 permutation = 0;
2037 unsigned int mode = 0;
2038 const float *lightcolorbase = rtlight->currentcolor;
2039 float ambientscale = rtlight->ambientscale;
2040 float diffusescale = rtlight->diffusescale;
2041 float specularscale = rtlight->specularscale;
2042 // this is the location of the light in view space
2043 vec3_t viewlightorigin;
2044 // this transforms from view space (camera) to light space (cubemap)
2045 matrix4x4_t viewtolight;
2046 matrix4x4_t lighttoview;
2047 float viewtolight16f[16];
2049 mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2050 if (rtlight->currentcubemap != r_texture_whitecube)
2051 permutation |= SHADERPERMUTATION_CUBEFILTER;
2052 if (diffusescale > 0)
2053 permutation |= SHADERPERMUTATION_DIFFUSE;
2054 if (specularscale > 0 && r_shadow_gloss.integer > 0)
2055 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2056 if (r_shadow_usingshadowmap2d)
2058 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2059 if (r_shadow_shadowmapvsdct)
2060 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2062 if (r_shadow_shadowmap2ddepthbuffer)
2063 permutation |= SHADERPERMUTATION_DEPTHRGB;
2065 if (vid.allowalphatocoverage)
2066 GL_AlphaToCoverage(false);
2067 Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2068 Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2069 Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2070 Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2071 switch(vid.renderpath)
2073 case RENDERPATH_GL32:
2074 case RENDERPATH_GLES2:
2075 R_SetupShader_SetPermutationGLSL(mode, permutation);
2076 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f( r_glsl_permutation->loc_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2077 if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight , 1, false, viewtolight16f);
2078 if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2079 if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2080 if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2081 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]);
2082 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]);
2083 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);
2084 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]);
2085 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/vid.width, 1.0f/vid.height);
2087 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2088 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2089 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2090 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2ddepthtexture );
2091 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2096 #define SKINFRAME_HASH 1024
2100 unsigned int loadsequence; // incremented each level change
2101 memexpandablearray_t array;
2102 skinframe_t *hash[SKINFRAME_HASH];
2105 r_skinframe_t r_skinframe;
2107 void R_SkinFrame_PrepareForPurge(void)
2109 r_skinframe.loadsequence++;
2110 // wrap it without hitting zero
2111 if (r_skinframe.loadsequence >= 200)
2112 r_skinframe.loadsequence = 1;
2115 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2119 // mark the skinframe as used for the purging code
2120 skinframe->loadsequence = r_skinframe.loadsequence;
2123 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2127 if (s->merged == s->base)
2129 R_PurgeTexture(s->stain); s->stain = NULL;
2130 R_PurgeTexture(s->merged); s->merged = NULL;
2131 R_PurgeTexture(s->base); s->base = NULL;
2132 R_PurgeTexture(s->pants); s->pants = NULL;
2133 R_PurgeTexture(s->shirt); s->shirt = NULL;
2134 R_PurgeTexture(s->nmap); s->nmap = NULL;
2135 R_PurgeTexture(s->gloss); s->gloss = NULL;
2136 R_PurgeTexture(s->glow); s->glow = NULL;
2137 R_PurgeTexture(s->fog); s->fog = NULL;
2138 R_PurgeTexture(s->reflect); s->reflect = NULL;
2139 s->loadsequence = 0;
2142 void R_SkinFrame_Purge(void)
2146 for (i = 0;i < SKINFRAME_HASH;i++)
2148 for (s = r_skinframe.hash[i];s;s = s->next)
2150 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2151 R_SkinFrame_PurgeSkinFrame(s);
2156 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2158 char basename[MAX_QPATH];
2160 Image_StripImageExtension(name, basename, sizeof(basename));
2162 if( last == NULL ) {
2164 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2165 item = r_skinframe.hash[hashindex];
2170 // linearly search through the hash bucket
2171 for( ; item ; item = item->next ) {
2172 if( !strcmp( item->basename, basename ) ) {
2179 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2182 int compareflags = textureflags & TEXF_IMPORTANTBITS;
2184 char basename[MAX_QPATH];
2186 Image_StripImageExtension(name, basename, sizeof(basename));
2188 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2189 for (item = r_skinframe.hash[hashindex];item;item = item->next)
2190 if (!strcmp(item->basename, basename) &&
2191 item->textureflags == compareflags &&
2192 item->comparewidth == comparewidth &&
2193 item->compareheight == compareheight &&
2194 item->comparecrc == comparecrc)
2201 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2202 memset(item, 0, sizeof(*item));
2203 strlcpy(item->basename, basename, sizeof(item->basename));
2204 item->textureflags = compareflags;
2205 item->comparewidth = comparewidth;
2206 item->compareheight = compareheight;
2207 item->comparecrc = comparecrc;
2208 item->next = r_skinframe.hash[hashindex];
2209 r_skinframe.hash[hashindex] = item;
2211 else if (textureflags & TEXF_FORCE_RELOAD)
2212 R_SkinFrame_PurgeSkinFrame(item);
2214 R_SkinFrame_MarkUsed(item);
2218 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2220 unsigned long long avgcolor[5], wsum; \
2228 for(pix = 0; pix < cnt; ++pix) \
2231 for(comp = 0; comp < 3; ++comp) \
2233 if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2236 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2238 for(comp = 0; comp < 3; ++comp) \
2239 avgcolor[comp] += getpixel * w; \
2242 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2243 avgcolor[4] += getpixel; \
2245 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2247 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2248 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2249 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2250 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2253 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2255 skinframe_t *skinframe;
2257 if (cls.state == ca_dedicated)
2260 // return an existing skinframe if already loaded
2261 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2262 if (skinframe && skinframe->base)
2265 // if the skinframe doesn't exist this will create it
2266 return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2269 extern cvar_t gl_picmip;
2270 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2273 unsigned char *pixels;
2274 unsigned char *bumppixels;
2275 unsigned char *basepixels = NULL;
2276 int basepixels_width = 0;
2277 int basepixels_height = 0;
2278 rtexture_t *ddsbase = NULL;
2279 qboolean ddshasalpha = false;
2280 float ddsavgcolor[4];
2281 char basename[MAX_QPATH];
2282 int miplevel = R_PicmipForFlags(textureflags);
2283 int savemiplevel = miplevel;
2287 if (cls.state == ca_dedicated)
2290 Image_StripImageExtension(name, basename, sizeof(basename));
2292 // check for DDS texture file first
2293 if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2295 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2296 if (basepixels == NULL && fallbacknotexture)
2297 basepixels = Image_GenerateNoTexture();
2298 if (basepixels == NULL)
2302 // FIXME handle miplevel
2304 if (developer_loading.integer)
2305 Con_Printf("loading skin \"%s\"\n", name);
2307 // we've got some pixels to store, so really allocate this new texture now
2309 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2310 textureflags &= ~TEXF_FORCE_RELOAD;
2311 skinframe->stain = NULL;
2312 skinframe->merged = NULL;
2313 skinframe->base = NULL;
2314 skinframe->pants = NULL;
2315 skinframe->shirt = NULL;
2316 skinframe->nmap = NULL;
2317 skinframe->gloss = NULL;
2318 skinframe->glow = NULL;
2319 skinframe->fog = NULL;
2320 skinframe->reflect = NULL;
2321 skinframe->hasalpha = false;
2322 // we could store the q2animname here too
2326 skinframe->base = ddsbase;
2327 skinframe->hasalpha = ddshasalpha;
2328 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2329 if (r_loadfog && skinframe->hasalpha)
2330 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);
2331 //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]);
2335 basepixels_width = image_width;
2336 basepixels_height = image_height;
2337 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);
2338 if (textureflags & TEXF_ALPHA)
2340 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2342 if (basepixels[j] < 255)
2344 skinframe->hasalpha = true;
2348 if (r_loadfog && skinframe->hasalpha)
2350 // has transparent pixels
2351 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2352 for (j = 0;j < image_width * image_height * 4;j += 4)
2357 pixels[j+3] = basepixels[j+3];
2359 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);
2363 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2365 //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]);
2366 if (r_savedds && skinframe->base)
2367 R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2368 if (r_savedds && skinframe->fog)
2369 R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2375 mymiplevel = savemiplevel;
2376 if (r_loadnormalmap)
2377 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);
2378 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2380 skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2381 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2382 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2383 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2386 // _norm is the name used by tenebrae and has been adopted as standard
2387 if (r_loadnormalmap && skinframe->nmap == NULL)
2389 mymiplevel = savemiplevel;
2390 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2392 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);
2396 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2398 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2399 Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2400 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);
2402 Mem_Free(bumppixels);
2404 else if (r_shadow_bumpscale_basetexture.value > 0)
2406 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2407 Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2408 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);
2412 if (r_savedds && skinframe->nmap)
2413 R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2417 // _luma is supported only for tenebrae compatibility
2418 // _glow is the preferred name
2419 mymiplevel = savemiplevel;
2420 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))))
2422 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);
2424 if (r_savedds && skinframe->glow)
2425 R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2427 Mem_Free(pixels);pixels = NULL;
2430 mymiplevel = savemiplevel;
2431 if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2433 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);
2435 if (r_savedds && skinframe->gloss)
2436 R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2442 mymiplevel = savemiplevel;
2443 if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2445 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);
2447 if (r_savedds && skinframe->pants)
2448 R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2454 mymiplevel = savemiplevel;
2455 if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2457 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);
2459 if (r_savedds && skinframe->shirt)
2460 R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2466 mymiplevel = savemiplevel;
2467 if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2469 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);
2471 if (r_savedds && skinframe->reflect)
2472 R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2479 Mem_Free(basepixels);
2484 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2487 skinframe_t *skinframe;
2490 if (cls.state == ca_dedicated)
2493 // if already loaded just return it, otherwise make a new skinframe
2494 skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2495 if (skinframe->base)
2497 textureflags &= ~TEXF_FORCE_RELOAD;
2499 skinframe->stain = NULL;
2500 skinframe->merged = NULL;
2501 skinframe->base = NULL;
2502 skinframe->pants = NULL;
2503 skinframe->shirt = NULL;
2504 skinframe->nmap = NULL;
2505 skinframe->gloss = NULL;
2506 skinframe->glow = NULL;
2507 skinframe->fog = NULL;
2508 skinframe->reflect = NULL;
2509 skinframe->hasalpha = false;
2511 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2515 if (developer_loading.integer)
2516 Con_Printf("loading 32bit skin \"%s\"\n", name);
2518 if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2520 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2521 unsigned char *b = a + width * height * 4;
2522 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2523 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);
2526 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2527 if (textureflags & TEXF_ALPHA)
2529 for (i = 3;i < width * height * 4;i += 4)
2531 if (skindata[i] < 255)
2533 skinframe->hasalpha = true;
2537 if (r_loadfog && skinframe->hasalpha)
2539 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2540 memcpy(fogpixels, skindata, width * height * 4);
2541 for (i = 0;i < width * height * 4;i += 4)
2542 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2543 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2544 Mem_Free(fogpixels);
2548 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2549 //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]);
2554 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2558 skinframe_t *skinframe;
2560 if (cls.state == ca_dedicated)
2563 // if already loaded just return it, otherwise make a new skinframe
2564 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2565 if (skinframe->base)
2567 //textureflags &= ~TEXF_FORCE_RELOAD;
2569 skinframe->stain = NULL;
2570 skinframe->merged = NULL;
2571 skinframe->base = NULL;
2572 skinframe->pants = NULL;
2573 skinframe->shirt = NULL;
2574 skinframe->nmap = NULL;
2575 skinframe->gloss = NULL;
2576 skinframe->glow = NULL;
2577 skinframe->fog = NULL;
2578 skinframe->reflect = NULL;
2579 skinframe->hasalpha = false;
2581 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2585 if (developer_loading.integer)
2586 Con_Printf("loading quake skin \"%s\"\n", name);
2588 // 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)
2589 skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2590 memcpy(skinframe->qpixels, skindata, width*height);
2591 skinframe->qwidth = width;
2592 skinframe->qheight = height;
2595 for (i = 0;i < width * height;i++)
2596 featuresmask |= palette_featureflags[skindata[i]];
2598 skinframe->hasalpha = false;
2601 skinframe->hasalpha = true;
2602 skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2603 skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2604 skinframe->qgeneratemerged = true;
2605 skinframe->qgeneratebase = skinframe->qhascolormapping;
2606 skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2608 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2609 //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]);
2614 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2618 unsigned char *skindata;
2621 if (!skinframe->qpixels)
2624 if (!skinframe->qhascolormapping)
2625 colormapped = false;
2629 if (!skinframe->qgeneratebase)
2634 if (!skinframe->qgeneratemerged)
2638 width = skinframe->qwidth;
2639 height = skinframe->qheight;
2640 skindata = skinframe->qpixels;
2642 if (skinframe->qgeneratenmap)
2644 unsigned char *a, *b;
2645 skinframe->qgeneratenmap = false;
2646 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2647 b = a + width * height * 4;
2648 // use either a custom palette or the quake palette
2649 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2650 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2651 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);
2655 if (skinframe->qgenerateglow)
2657 skinframe->qgenerateglow = false;
2658 if (skinframe->hasalpha) // fence textures
2659 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
2661 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
2666 skinframe->qgeneratebase = false;
2667 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);
2668 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);
2669 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);
2673 skinframe->qgeneratemerged = false;
2674 if (skinframe->hasalpha) // fence textures
2675 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);
2677 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);
2680 if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2682 Mem_Free(skinframe->qpixels);
2683 skinframe->qpixels = NULL;
2687 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)
2690 skinframe_t *skinframe;
2693 if (cls.state == ca_dedicated)
2696 // if already loaded just return it, otherwise make a new skinframe
2697 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2698 if (skinframe->base)
2700 textureflags &= ~TEXF_FORCE_RELOAD;
2702 skinframe->stain = NULL;
2703 skinframe->merged = NULL;
2704 skinframe->base = NULL;
2705 skinframe->pants = NULL;
2706 skinframe->shirt = NULL;
2707 skinframe->nmap = NULL;
2708 skinframe->gloss = NULL;
2709 skinframe->glow = NULL;
2710 skinframe->fog = NULL;
2711 skinframe->reflect = NULL;
2712 skinframe->hasalpha = false;
2714 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2718 if (developer_loading.integer)
2719 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2721 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2722 if ((textureflags & TEXF_ALPHA) && alphapalette)
2724 for (i = 0;i < width * height;i++)
2726 if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2728 skinframe->hasalpha = true;
2732 if (r_loadfog && skinframe->hasalpha)
2733 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2736 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2737 //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]);
2742 skinframe_t *R_SkinFrame_LoadMissing(void)
2744 skinframe_t *skinframe;
2746 if (cls.state == ca_dedicated)
2749 skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2750 skinframe->stain = NULL;
2751 skinframe->merged = NULL;
2752 skinframe->base = NULL;
2753 skinframe->pants = NULL;
2754 skinframe->shirt = NULL;
2755 skinframe->nmap = NULL;
2756 skinframe->gloss = NULL;
2757 skinframe->glow = NULL;
2758 skinframe->fog = NULL;
2759 skinframe->reflect = NULL;
2760 skinframe->hasalpha = false;
2762 skinframe->avgcolor[0] = rand() / RAND_MAX;
2763 skinframe->avgcolor[1] = rand() / RAND_MAX;
2764 skinframe->avgcolor[2] = rand() / RAND_MAX;
2765 skinframe->avgcolor[3] = 1;
2770 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2773 static unsigned char pix[16][16][4];
2775 if (cls.state == ca_dedicated)
2778 // this makes a light grey/dark grey checkerboard texture
2781 for (y = 0; y < 16; y++)
2783 for (x = 0; x < 16; x++)
2785 if ((y < 8) ^ (x < 8))
2803 return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2806 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2808 skinframe_t *skinframe;
2809 if (cls.state == ca_dedicated)
2811 // if already loaded just return it, otherwise make a new skinframe
2812 skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2813 if (skinframe->base)
2815 textureflags &= ~TEXF_FORCE_RELOAD;
2816 skinframe->stain = NULL;
2817 skinframe->merged = NULL;
2818 skinframe->base = NULL;
2819 skinframe->pants = NULL;
2820 skinframe->shirt = NULL;
2821 skinframe->nmap = NULL;
2822 skinframe->gloss = NULL;
2823 skinframe->glow = NULL;
2824 skinframe->fog = NULL;
2825 skinframe->reflect = NULL;
2826 skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2827 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2830 if (developer_loading.integer)
2831 Con_Printf("loading 32bit skin \"%s\"\n", name);
2832 skinframe->base = skinframe->merged = tex;
2833 Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2837 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2838 typedef struct suffixinfo_s
2841 qboolean flipx, flipy, flipdiagonal;
2844 static suffixinfo_t suffix[3][6] =
2847 {"px", false, false, false},
2848 {"nx", false, false, false},
2849 {"py", false, false, false},
2850 {"ny", false, false, false},
2851 {"pz", false, false, false},
2852 {"nz", false, false, false}
2855 {"posx", false, false, false},
2856 {"negx", false, false, false},
2857 {"posy", false, false, false},
2858 {"negy", false, false, false},
2859 {"posz", false, false, false},
2860 {"negz", false, false, false}
2863 {"rt", true, false, true},
2864 {"lf", false, true, true},
2865 {"ft", true, true, false},
2866 {"bk", false, false, false},
2867 {"up", true, false, true},
2868 {"dn", true, false, true}
2872 static int componentorder[4] = {0, 1, 2, 3};
2874 static rtexture_t *R_LoadCubemap(const char *basename)
2876 int i, j, cubemapsize;
2877 unsigned char *cubemappixels, *image_buffer;
2878 rtexture_t *cubemaptexture;
2880 // must start 0 so the first loadimagepixels has no requested width/height
2882 cubemappixels = NULL;
2883 cubemaptexture = NULL;
2884 // keep trying different suffix groups (posx, px, rt) until one loads
2885 for (j = 0;j < 3 && !cubemappixels;j++)
2887 // load the 6 images in the suffix group
2888 for (i = 0;i < 6;i++)
2890 // generate an image name based on the base and and suffix
2891 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2893 if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2895 // an image loaded, make sure width and height are equal
2896 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2898 // if this is the first image to load successfully, allocate the cubemap memory
2899 if (!cubemappixels && image_width >= 1)
2901 cubemapsize = image_width;
2902 // note this clears to black, so unavailable sides are black
2903 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2905 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2907 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);
2910 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2912 Mem_Free(image_buffer);
2916 // if a cubemap loaded, upload it
2919 if (developer_loading.integer)
2920 Con_Printf("loading cubemap \"%s\"\n", basename);
2922 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);
2923 Mem_Free(cubemappixels);
2927 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2928 if (developer_loading.integer)
2930 Con_Printf("(tried tried images ");
2931 for (j = 0;j < 3;j++)
2932 for (i = 0;i < 6;i++)
2933 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2934 Con_Print(" and was unable to find any of them).\n");
2937 return cubemaptexture;
2940 rtexture_t *R_GetCubemap(const char *basename)
2943 for (i = 0;i < r_texture_numcubemaps;i++)
2944 if (r_texture_cubemaps[i] != NULL)
2945 if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2946 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2947 if (i >= MAX_CUBEMAPS || !r_main_mempool)
2948 return r_texture_whitecube;
2949 r_texture_numcubemaps++;
2950 r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2951 strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2952 r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2953 return r_texture_cubemaps[i]->texture;
2956 static void R_Main_FreeViewCache(void)
2958 if (r_refdef.viewcache.entityvisible)
2959 Mem_Free(r_refdef.viewcache.entityvisible);
2960 if (r_refdef.viewcache.world_pvsbits)
2961 Mem_Free(r_refdef.viewcache.world_pvsbits);
2962 if (r_refdef.viewcache.world_leafvisible)
2963 Mem_Free(r_refdef.viewcache.world_leafvisible);
2964 if (r_refdef.viewcache.world_surfacevisible)
2965 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2966 memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2969 static void R_Main_ResizeViewCache(void)
2971 int numentities = r_refdef.scene.numentities;
2972 int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2973 int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2974 int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2975 int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2976 if (r_refdef.viewcache.maxentities < numentities)
2978 r_refdef.viewcache.maxentities = numentities;
2979 if (r_refdef.viewcache.entityvisible)
2980 Mem_Free(r_refdef.viewcache.entityvisible);
2981 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2983 if (r_refdef.viewcache.world_numclusters != numclusters)
2985 r_refdef.viewcache.world_numclusters = numclusters;
2986 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2987 if (r_refdef.viewcache.world_pvsbits)
2988 Mem_Free(r_refdef.viewcache.world_pvsbits);
2989 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
2991 if (r_refdef.viewcache.world_numleafs != numleafs)
2993 r_refdef.viewcache.world_numleafs = numleafs;
2994 if (r_refdef.viewcache.world_leafvisible)
2995 Mem_Free(r_refdef.viewcache.world_leafvisible);
2996 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
2998 if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3000 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3001 if (r_refdef.viewcache.world_surfacevisible)
3002 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3003 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3007 extern rtexture_t *loadingscreentexture;
3008 static void gl_main_start(void)
3010 loadingscreentexture = NULL;
3011 r_texture_blanknormalmap = NULL;
3012 r_texture_white = NULL;
3013 r_texture_grey128 = NULL;
3014 r_texture_black = NULL;
3015 r_texture_whitecube = NULL;
3016 r_texture_normalizationcube = NULL;
3017 r_texture_fogattenuation = NULL;
3018 r_texture_fogheighttexture = NULL;
3019 r_texture_gammaramps = NULL;
3020 r_texture_numcubemaps = 0;
3021 r_uniformbufferalignment = 32;
3023 r_loaddds = r_texture_dds_load.integer != 0;
3024 r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3026 switch(vid.renderpath)
3028 case RENDERPATH_GL32:
3029 case RENDERPATH_GLES2:
3030 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3031 Cvar_SetValueQuick(&gl_combine, 1);
3032 Cvar_SetValueQuick(&r_glsl, 1);
3033 r_loadnormalmap = true;
3036 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3037 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3043 R_FrameData_Reset();
3044 R_BufferData_Reset();
3048 memset(r_queries, 0, sizeof(r_queries));
3050 r_qwskincache = NULL;
3051 r_qwskincache_size = 0;
3053 // due to caching of texture_t references, the collision cache must be reset
3054 Collision_Cache_Reset(true);
3056 // set up r_skinframe loading system for textures
3057 memset(&r_skinframe, 0, sizeof(r_skinframe));
3058 r_skinframe.loadsequence = 1;
3059 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3061 r_main_texturepool = R_AllocTexturePool();
3062 R_BuildBlankTextures();
3065 R_BuildNormalizationCube();
3066 r_texture_fogattenuation = NULL;
3067 r_texture_fogheighttexture = NULL;
3068 r_texture_gammaramps = NULL;
3069 //r_texture_fogintensity = NULL;
3070 memset(&r_fb, 0, sizeof(r_fb));
3071 Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3072 r_glsl_permutation = NULL;
3073 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3074 Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3075 memset(&r_svbsp, 0, sizeof (r_svbsp));
3077 memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3078 r_texture_numcubemaps = 0;
3080 r_refdef.fogmasktable_density = 0;
3083 // For Steelstorm Android
3084 // FIXME CACHE the program and reload
3085 // FIXME see possible combinations for SS:BR android
3086 Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3087 R_SetupShader_SetPermutationGLSL(0, 12);
3088 R_SetupShader_SetPermutationGLSL(0, 13);
3089 R_SetupShader_SetPermutationGLSL(0, 8388621);
3090 R_SetupShader_SetPermutationGLSL(3, 0);
3091 R_SetupShader_SetPermutationGLSL(3, 2048);
3092 R_SetupShader_SetPermutationGLSL(5, 0);
3093 R_SetupShader_SetPermutationGLSL(5, 2);
3094 R_SetupShader_SetPermutationGLSL(5, 2048);
3095 R_SetupShader_SetPermutationGLSL(5, 8388608);
3096 R_SetupShader_SetPermutationGLSL(11, 1);
3097 R_SetupShader_SetPermutationGLSL(11, 2049);
3098 R_SetupShader_SetPermutationGLSL(11, 8193);
3099 R_SetupShader_SetPermutationGLSL(11, 10241);
3100 Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3104 static void gl_main_shutdown(void)
3106 R_RenderTarget_FreeUnused(true);
3107 Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3109 R_FrameData_Reset();
3110 R_BufferData_Reset();
3112 R_Main_FreeViewCache();
3114 switch(vid.renderpath)
3116 case RENDERPATH_GL32:
3117 case RENDERPATH_GLES2:
3118 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3120 qglDeleteQueries(r_maxqueries, r_queries);
3127 memset(r_queries, 0, sizeof(r_queries));
3129 r_qwskincache = NULL;
3130 r_qwskincache_size = 0;
3132 // clear out the r_skinframe state
3133 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3134 memset(&r_skinframe, 0, sizeof(r_skinframe));
3137 Mem_Free(r_svbsp.nodes);
3138 memset(&r_svbsp, 0, sizeof (r_svbsp));
3139 R_FreeTexturePool(&r_main_texturepool);
3140 loadingscreentexture = NULL;
3141 r_texture_blanknormalmap = NULL;
3142 r_texture_white = NULL;
3143 r_texture_grey128 = NULL;
3144 r_texture_black = NULL;
3145 r_texture_whitecube = NULL;
3146 r_texture_normalizationcube = NULL;
3147 r_texture_fogattenuation = NULL;
3148 r_texture_fogheighttexture = NULL;
3149 r_texture_gammaramps = NULL;
3150 r_texture_numcubemaps = 0;
3151 //r_texture_fogintensity = NULL;
3152 memset(&r_fb, 0, sizeof(r_fb));
3155 r_glsl_permutation = NULL;
3156 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3157 Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3160 static void gl_main_newmap(void)
3162 // FIXME: move this code to client
3163 char *entities, entname[MAX_QPATH];
3165 Mem_Free(r_qwskincache);
3166 r_qwskincache = NULL;
3167 r_qwskincache_size = 0;
3170 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3171 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3173 CL_ParseEntityLump(entities);
3177 if (cl.worldmodel->brush.entities)
3178 CL_ParseEntityLump(cl.worldmodel->brush.entities);
3180 R_Main_FreeViewCache();
3182 R_FrameData_Reset();
3183 R_BufferData_Reset();
3186 void GL_Main_Init(void)
3189 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3190 R_InitShaderModeInfo();
3192 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3193 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3194 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3195 if (gamemode == GAME_NEHAHRA)
3197 Cvar_RegisterVariable (&gl_fogenable);
3198 Cvar_RegisterVariable (&gl_fogdensity);
3199 Cvar_RegisterVariable (&gl_fogred);
3200 Cvar_RegisterVariable (&gl_foggreen);
3201 Cvar_RegisterVariable (&gl_fogblue);
3202 Cvar_RegisterVariable (&gl_fogstart);
3203 Cvar_RegisterVariable (&gl_fogend);
3204 Cvar_RegisterVariable (&gl_skyclip);
3206 Cvar_RegisterVariable(&r_motionblur);
3207 Cvar_RegisterVariable(&r_damageblur);
3208 Cvar_RegisterVariable(&r_motionblur_averaging);
3209 Cvar_RegisterVariable(&r_motionblur_randomize);
3210 Cvar_RegisterVariable(&r_motionblur_minblur);
3211 Cvar_RegisterVariable(&r_motionblur_maxblur);
3212 Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3213 Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3214 Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3215 Cvar_RegisterVariable(&r_motionblur_mousefactor);
3216 Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3217 Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3218 Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3219 Cvar_RegisterVariable(&r_equalize_entities_minambient);
3220 Cvar_RegisterVariable(&r_equalize_entities_by);
3221 Cvar_RegisterVariable(&r_equalize_entities_to);
3222 Cvar_RegisterVariable(&r_depthfirst);
3223 Cvar_RegisterVariable(&r_useinfinitefarclip);
3224 Cvar_RegisterVariable(&r_farclip_base);
3225 Cvar_RegisterVariable(&r_farclip_world);
3226 Cvar_RegisterVariable(&r_nearclip);
3227 Cvar_RegisterVariable(&r_deformvertexes);
3228 Cvar_RegisterVariable(&r_transparent);
3229 Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3230 Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3231 Cvar_RegisterVariable(&r_transparent_useplanardistance);
3232 Cvar_RegisterVariable(&r_showoverdraw);
3233 Cvar_RegisterVariable(&r_showbboxes);
3234 Cvar_RegisterVariable(&r_showbboxes_client);
3235 Cvar_RegisterVariable(&r_showsurfaces);
3236 Cvar_RegisterVariable(&r_showtris);
3237 Cvar_RegisterVariable(&r_shownormals);
3238 Cvar_RegisterVariable(&r_showlighting);
3239 Cvar_RegisterVariable(&r_showcollisionbrushes);
3240 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3241 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3242 Cvar_RegisterVariable(&r_showdisabledepthtest);
3243 Cvar_RegisterVariable(&r_showspriteedges);
3244 Cvar_RegisterVariable(&r_showparticleedges);
3245 Cvar_RegisterVariable(&r_drawportals);
3246 Cvar_RegisterVariable(&r_drawentities);
3247 Cvar_RegisterVariable(&r_draw2d);
3248 Cvar_RegisterVariable(&r_drawworld);
3249 Cvar_RegisterVariable(&r_cullentities_trace);
3250 Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3251 Cvar_RegisterVariable(&r_cullentities_trace_samples);
3252 Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3253 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3254 Cvar_RegisterVariable(&r_cullentities_trace_expand);
3255 Cvar_RegisterVariable(&r_cullentities_trace_pad);
3256 Cvar_RegisterVariable(&r_cullentities_trace_delay);
3257 Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3258 Cvar_RegisterVariable(&r_sortentities);
3259 Cvar_RegisterVariable(&r_drawviewmodel);
3260 Cvar_RegisterVariable(&r_drawexteriormodel);
3261 Cvar_RegisterVariable(&r_speeds);
3262 Cvar_RegisterVariable(&r_fullbrights);
3263 Cvar_RegisterVariable(&r_wateralpha);
3264 Cvar_RegisterVariable(&r_dynamic);
3265 Cvar_RegisterVariable(&r_fakelight);
3266 Cvar_RegisterVariable(&r_fakelight_intensity);
3267 Cvar_RegisterVariable(&r_fullbright_directed);
3268 Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3269 Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3270 Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3271 Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3272 Cvar_RegisterVariable(&r_fullbright);
3273 Cvar_RegisterVariable(&r_shadows);
3274 Cvar_RegisterVariable(&r_shadows_darken);
3275 Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3276 Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3277 Cvar_RegisterVariable(&r_shadows_throwdistance);
3278 Cvar_RegisterVariable(&r_shadows_throwdirection);
3279 Cvar_RegisterVariable(&r_shadows_focus);
3280 Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3281 Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3282 Cvar_RegisterVariable(&r_q1bsp_skymasking);
3283 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3284 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3285 Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3286 Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3287 Cvar_RegisterVariable(&r_fog_exp2);
3288 Cvar_RegisterVariable(&r_fog_clear);
3289 Cvar_RegisterVariable(&r_drawfog);
3290 Cvar_RegisterVariable(&r_transparentdepthmasking);
3291 Cvar_RegisterVariable(&r_transparent_sortmindist);
3292 Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3293 Cvar_RegisterVariable(&r_transparent_sortarraysize);
3294 Cvar_RegisterVariable(&r_texture_dds_load);
3295 Cvar_RegisterVariable(&r_texture_dds_save);
3296 Cvar_RegisterVariable(&r_textureunits);
3297 Cvar_RegisterVariable(&gl_combine);
3298 Cvar_RegisterVariable(&r_usedepthtextures);
3299 Cvar_RegisterVariable(&r_viewfbo);
3300 Cvar_RegisterVariable(&r_rendertarget_debug);
3301 Cvar_RegisterVariable(&r_viewscale);
3302 Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3303 Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3304 Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3305 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3306 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3307 Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3308 Cvar_RegisterVariable(&r_glsl);
3309 Cvar_RegisterVariable(&r_glsl_deluxemapping);
3310 Cvar_RegisterVariable(&r_glsl_offsetmapping);
3311 Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3312 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3313 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3314 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3315 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3316 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3317 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3318 Cvar_RegisterVariable(&r_glsl_postprocess);
3319 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3320 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3321 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3322 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3323 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3324 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3325 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3326 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3327 Cvar_RegisterVariable(&r_celshading);
3328 Cvar_RegisterVariable(&r_celoutlines);
3330 Cvar_RegisterVariable(&r_water);
3331 Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3332 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3333 Cvar_RegisterVariable(&r_water_clippingplanebias);
3334 Cvar_RegisterVariable(&r_water_refractdistort);
3335 Cvar_RegisterVariable(&r_water_reflectdistort);
3336 Cvar_RegisterVariable(&r_water_scissormode);
3337 Cvar_RegisterVariable(&r_water_lowquality);
3338 Cvar_RegisterVariable(&r_water_hideplayer);
3340 Cvar_RegisterVariable(&r_lerpsprites);
3341 Cvar_RegisterVariable(&r_lerpmodels);
3342 Cvar_RegisterVariable(&r_lerplightstyles);
3343 Cvar_RegisterVariable(&r_waterscroll);
3344 Cvar_RegisterVariable(&r_bloom);
3345 Cvar_RegisterVariable(&r_bloom_colorscale);
3346 Cvar_RegisterVariable(&r_bloom_brighten);
3347 Cvar_RegisterVariable(&r_bloom_blur);
3348 Cvar_RegisterVariable(&r_bloom_resolution);
3349 Cvar_RegisterVariable(&r_bloom_colorexponent);
3350 Cvar_RegisterVariable(&r_bloom_colorsubtract);
3351 Cvar_RegisterVariable(&r_bloom_scenebrightness);
3352 Cvar_RegisterVariable(&r_hdr_scenebrightness);
3353 Cvar_RegisterVariable(&r_hdr_glowintensity);
3354 Cvar_RegisterVariable(&r_hdr_irisadaptation);
3355 Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3356 Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3357 Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3358 Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3359 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3360 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3361 Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3362 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3363 Cvar_RegisterVariable(&developer_texturelogging);
3364 Cvar_RegisterVariable(&gl_lightmaps);
3365 Cvar_RegisterVariable(&r_test);
3366 Cvar_RegisterVariable(&r_batch_multidraw);
3367 Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3368 Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3369 Cvar_RegisterVariable(&r_glsl_skeletal);
3370 Cvar_RegisterVariable(&r_glsl_saturation);
3371 Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3372 Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3373 Cvar_RegisterVariable(&r_framedatasize);
3374 for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3375 Cvar_RegisterVariable(&r_buffermegs[i]);
3376 Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3377 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3378 Cvar_SetValue("r_fullbrights", 0);
3379 #ifdef DP_MOBILETOUCH
3380 // GLES devices have terrible depth precision in general, so...
3381 Cvar_SetValueQuick(&r_nearclip, 4);
3382 Cvar_SetValueQuick(&r_farclip_base, 4096);
3383 Cvar_SetValueQuick(&r_farclip_world, 0);
3384 Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3386 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3389 void Render_Init(void)
3402 R_LightningBeams_Init();
3406 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3410 if (r_trippy.integer)
3412 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3414 p = r_refdef.view.frustum + i;
3419 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3423 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3427 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3431 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3435 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3439 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3443 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3447 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3455 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3459 if (r_trippy.integer)
3461 for (i = 0;i < numplanes;i++)
3468 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3472 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3476 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3480 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3484 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3488 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3492 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3496 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3504 //==================================================================================
3506 // LordHavoc: this stores temporary data used within the same frame
3508 typedef struct r_framedata_mem_s
3510 struct r_framedata_mem_s *purge; // older mem block to free on next frame
3511 size_t size; // how much usable space
3512 size_t current; // how much space in use
3513 size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3514 size_t wantedsize; // how much space was allocated
3515 unsigned char *data; // start of real data (16byte aligned)
3519 static r_framedata_mem_t *r_framedata_mem;
3521 void R_FrameData_Reset(void)
3523 while (r_framedata_mem)
3525 r_framedata_mem_t *next = r_framedata_mem->purge;
3526 Mem_Free(r_framedata_mem);
3527 r_framedata_mem = next;
3531 static void R_FrameData_Resize(qboolean mustgrow)
3534 wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3535 wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3536 if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3538 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3539 newmem->wantedsize = wantedsize;
3540 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3541 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3542 newmem->current = 0;
3544 newmem->purge = r_framedata_mem;
3545 r_framedata_mem = newmem;
3549 void R_FrameData_NewFrame(void)
3551 R_FrameData_Resize(false);
3552 if (!r_framedata_mem)
3554 // if we ran out of space on the last frame, free the old memory now
3555 while (r_framedata_mem->purge)
3557 // repeatedly remove the second item in the list, leaving only head
3558 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3559 Mem_Free(r_framedata_mem->purge);
3560 r_framedata_mem->purge = next;
3562 // reset the current mem pointer
3563 r_framedata_mem->current = 0;
3564 r_framedata_mem->mark = 0;
3567 void *R_FrameData_Alloc(size_t size)
3572 // align to 16 byte boundary - the data pointer is already aligned, so we
3573 // only need to ensure the size of every allocation is also aligned
3574 size = (size + 15) & ~15;
3576 while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3578 // emergency - we ran out of space, allocate more memory
3579 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3580 newvalue = r_framedatasize.value * 2.0f;
3581 // 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
3582 if (sizeof(size_t) >= 8)
3583 newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3585 newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3586 // this might not be a growing it, but we'll allocate another buffer every time
3587 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3588 R_FrameData_Resize(true);
3591 data = r_framedata_mem->data + r_framedata_mem->current;
3592 r_framedata_mem->current += size;
3594 // count the usage for stats
3595 r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3596 r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3598 return (void *)data;
3601 void *R_FrameData_Store(size_t size, void *data)
3603 void *d = R_FrameData_Alloc(size);
3605 memcpy(d, data, size);
3609 void R_FrameData_SetMark(void)
3611 if (!r_framedata_mem)
3613 r_framedata_mem->mark = r_framedata_mem->current;
3616 void R_FrameData_ReturnToMark(void)
3618 if (!r_framedata_mem)
3620 r_framedata_mem->current = r_framedata_mem->mark;
3623 //==================================================================================
3625 // avoid reusing the same buffer objects on consecutive frames
3626 #define R_BUFFERDATA_CYCLE 3
3628 typedef struct r_bufferdata_buffer_s
3630 struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3631 size_t size; // how much usable space
3632 size_t current; // how much space in use
3633 r_meshbuffer_t *buffer; // the buffer itself
3635 r_bufferdata_buffer_t;
3637 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3638 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3640 /// frees all dynamic buffers
3641 void R_BufferData_Reset(void)
3644 r_bufferdata_buffer_t **p, *mem;
3645 for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3647 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3650 p = &r_bufferdata_buffer[cycle][type];
3656 R_Mesh_DestroyMeshBuffer(mem->buffer);
3663 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3664 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3666 r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3668 float newvalue = r_buffermegs[type].value;
3670 // increase the cvar if we have to (but only if we already have a mem)
3671 if (mustgrow && mem)
3673 newvalue = bound(0.25f, newvalue, 256.0f);
3674 while (newvalue * 1024*1024 < minsize)
3677 // clamp the cvar to valid range
3678 newvalue = bound(0.25f, newvalue, 256.0f);
3679 if (r_buffermegs[type].value != newvalue)
3680 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3682 // calculate size in bytes
3683 size = (size_t)(newvalue * 1024*1024);
3684 size = bound(131072, size, 256*1024*1024);
3686 // allocate a new buffer if the size is different (purge old one later)
3687 // or if we were told we must grow the buffer
3688 if (!mem || mem->size != size || mustgrow)
3690 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3693 if (type == R_BUFFERDATA_VERTEX)
3694 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3695 else if (type == R_BUFFERDATA_INDEX16)
3696 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3697 else if (type == R_BUFFERDATA_INDEX32)
3698 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3699 else if (type == R_BUFFERDATA_UNIFORM)
3700 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3701 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3702 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3706 void R_BufferData_NewFrame(void)
3709 r_bufferdata_buffer_t **p, *mem;
3710 // cycle to the next frame's buffers
3711 r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3712 // if we ran out of space on the last time we used these buffers, free the old memory now
3713 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3715 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3717 R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3718 // free all but the head buffer, this is how we recycle obsolete
3719 // buffers after they are no longer in use
3720 p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3726 R_Mesh_DestroyMeshBuffer(mem->buffer);
3729 // reset the current offset
3730 r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3735 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3737 r_bufferdata_buffer_t *mem;
3741 *returnbufferoffset = 0;
3743 // align size to a byte boundary appropriate for the buffer type, this
3744 // makes all allocations have aligned start offsets
3745 if (type == R_BUFFERDATA_UNIFORM)
3746 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3748 padsize = (datasize + 15) & ~15;
3750 // if we ran out of space in this buffer we must allocate a new one
3751 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)
3752 R_BufferData_Resize(type, true, padsize);
3754 // if the resize did not give us enough memory, fail
3755 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)
3756 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3758 mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3759 offset = (int)mem->current;
3760 mem->current += padsize;
3762 // upload the data to the buffer at the chosen offset
3764 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3765 R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3767 // count the usage for stats
3768 r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3769 r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3771 // return the buffer offset
3772 *returnbufferoffset = offset;
3777 //==================================================================================
3779 // LordHavoc: animcache originally written by Echon, rewritten since then
3782 * Animation cache prevents re-generating mesh data for an animated model
3783 * multiple times in one frame for lighting, shadowing, reflections, etc.
3786 void R_AnimCache_Free(void)
3790 void R_AnimCache_ClearCache(void)
3793 entity_render_t *ent;
3795 for (i = 0;i < r_refdef.scene.numentities;i++)
3797 ent = r_refdef.scene.entities[i];
3798 ent->animcache_vertex3f = NULL;
3799 ent->animcache_vertex3f_vertexbuffer = NULL;
3800 ent->animcache_vertex3f_bufferoffset = 0;
3801 ent->animcache_normal3f = NULL;
3802 ent->animcache_normal3f_vertexbuffer = NULL;
3803 ent->animcache_normal3f_bufferoffset = 0;
3804 ent->animcache_svector3f = NULL;
3805 ent->animcache_svector3f_vertexbuffer = NULL;
3806 ent->animcache_svector3f_bufferoffset = 0;
3807 ent->animcache_tvector3f = NULL;
3808 ent->animcache_tvector3f_vertexbuffer = NULL;
3809 ent->animcache_tvector3f_bufferoffset = 0;
3810 ent->animcache_skeletaltransform3x4 = NULL;
3811 ent->animcache_skeletaltransform3x4buffer = NULL;
3812 ent->animcache_skeletaltransform3x4offset = 0;
3813 ent->animcache_skeletaltransform3x4size = 0;
3817 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3819 dp_model_t *model = ent->model;
3822 // see if this ent is worth caching
3823 if (!model || !model->Draw || !model->AnimateVertices)
3825 // nothing to cache if it contains no animations and has no skeleton
3826 if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3828 // see if it is already cached for gpuskeletal
3829 if (ent->animcache_skeletaltransform3x4)
3831 // see if it is already cached as a mesh
3832 if (ent->animcache_vertex3f)
3834 // check if we need to add normals or tangents
3835 if (ent->animcache_normal3f)
3836 wantnormals = false;
3837 if (ent->animcache_svector3f)
3838 wanttangents = false;
3839 if (!wantnormals && !wanttangents)
3843 // check which kind of cache we need to generate
3844 if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3846 // cache the skeleton so the vertex shader can use it
3847 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3848 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3849 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3850 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3851 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3852 // note: this can fail if the buffer is at the grow limit
3853 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3854 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3856 else if (ent->animcache_vertex3f)
3858 // mesh was already cached but we may need to add normals/tangents
3859 // (this only happens with multiple views, reflections, cameras, etc)
3860 if (wantnormals || wanttangents)
3862 numvertices = model->surfmesh.num_vertices;
3864 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3867 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3868 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3870 model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3871 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3872 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3873 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3878 // generate mesh cache
3879 numvertices = model->surfmesh.num_vertices;
3880 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3882 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3885 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3886 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3888 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3889 if (wantnormals || wanttangents)
3891 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3892 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3893 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3895 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3896 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3897 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3902 void R_AnimCache_CacheVisibleEntities(void)
3906 // TODO: thread this
3907 // NOTE: R_PrepareRTLights() also caches entities
3909 for (i = 0;i < r_refdef.scene.numentities;i++)
3910 if (r_refdef.viewcache.entityvisible[i])
3911 R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3914 //==================================================================================
3916 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)
3919 vec3_t eyemins, eyemaxs;
3920 vec3_t boxmins, boxmaxs;
3921 vec3_t padmins, padmaxs;
3924 dp_model_t *model = r_refdef.scene.worldmodel;
3925 static vec3_t positions[] = {
3926 { 0.5f, 0.5f, 0.5f },
3927 { 0.0f, 0.0f, 0.0f },
3928 { 0.0f, 0.0f, 1.0f },
3929 { 0.0f, 1.0f, 0.0f },
3930 { 0.0f, 1.0f, 1.0f },
3931 { 1.0f, 0.0f, 0.0f },
3932 { 1.0f, 0.0f, 1.0f },
3933 { 1.0f, 1.0f, 0.0f },
3934 { 1.0f, 1.0f, 1.0f },
3937 // sample count can be set to -1 to skip this logic, for flicker-prone objects
3941 // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3942 if (!r_refdef.view.usevieworiginculling)
3945 if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3948 // expand the eye box a little
3949 eyemins[0] = eye[0] - eyejitter;
3950 eyemaxs[0] = eye[0] + eyejitter;
3951 eyemins[1] = eye[1] - eyejitter;
3952 eyemaxs[1] = eye[1] + eyejitter;
3953 eyemins[2] = eye[2] - eyejitter;
3954 eyemaxs[2] = eye[2] + eyejitter;
3955 // expand the box a little
3956 boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3957 boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3958 boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3959 boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3960 boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3961 boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3962 // make an even larger box for the acceptable area
3963 padmins[0] = boxmins[0] - pad;
3964 padmaxs[0] = boxmaxs[0] + pad;
3965 padmins[1] = boxmins[1] - pad;
3966 padmaxs[1] = boxmaxs[1] + pad;
3967 padmins[2] = boxmins[2] - pad;
3968 padmaxs[2] = boxmaxs[2] + pad;
3970 // return true if eye overlaps enlarged box
3971 if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3974 // try specific positions in the box first - note that these can be cached
3975 if (r_cullentities_trace_entityocclusion.integer)
3977 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3979 VectorCopy(eye, start);
3980 end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3981 end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3982 end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3983 //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
3984 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3985 // not picky - if the trace ended anywhere in the box we're good
3986 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3990 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3993 // try various random positions
3994 for (i = 0; i < numsamples; i++)
3996 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3997 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3998 if (r_cullentities_trace_entityocclusion.integer)
4000 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4001 // not picky - if the trace ended anywhere in the box we're good
4002 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4005 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4013 static void R_View_UpdateEntityVisible (void)
4018 entity_render_t *ent;
4020 if (r_refdef.envmap || r_fb.water.hideplayer)
4021 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4022 else if (chase_active.integer || r_fb.water.renderingscene)
4023 renderimask = RENDER_VIEWMODEL;
4025 renderimask = RENDER_EXTERIORMODEL;
4026 if (!r_drawviewmodel.integer)
4027 renderimask |= RENDER_VIEWMODEL;
4028 if (!r_drawexteriormodel.integer)
4029 renderimask |= RENDER_EXTERIORMODEL;
4030 memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4031 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4033 // worldmodel can check visibility
4034 for (i = 0;i < r_refdef.scene.numentities;i++)
4036 ent = r_refdef.scene.entities[i];
4037 if (!(ent->flags & renderimask))
4038 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)))
4039 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))
4040 r_refdef.viewcache.entityvisible[i] = true;
4045 // no worldmodel or it can't check visibility
4046 for (i = 0;i < r_refdef.scene.numentities;i++)
4048 ent = r_refdef.scene.entities[i];
4049 if (!(ent->flags & renderimask))
4050 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)))
4051 r_refdef.viewcache.entityvisible[i] = true;
4054 if (r_cullentities_trace.integer)
4056 for (i = 0;i < r_refdef.scene.numentities;i++)
4058 if (!r_refdef.viewcache.entityvisible[i])
4060 ent = r_refdef.scene.entities[i];
4061 if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4063 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4064 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))
4065 ent->last_trace_visibility = realtime;
4066 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4067 r_refdef.viewcache.entityvisible[i] = 0;
4073 /// only used if skyrendermasked, and normally returns false
4074 static int R_DrawBrushModelsSky (void)
4077 entity_render_t *ent;
4080 for (i = 0;i < r_refdef.scene.numentities;i++)
4082 if (!r_refdef.viewcache.entityvisible[i])
4084 ent = r_refdef.scene.entities[i];
4085 if (!ent->model || !ent->model->DrawSky)
4087 ent->model->DrawSky(ent);
4093 static void R_DrawNoModel(entity_render_t *ent);
4094 static void R_DrawModels(void)
4097 entity_render_t *ent;
4099 for (i = 0;i < r_refdef.scene.numentities;i++)
4101 if (!r_refdef.viewcache.entityvisible[i])
4103 ent = r_refdef.scene.entities[i];
4104 r_refdef.stats[r_stat_entities]++;
4106 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4109 Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4110 Con_Printf("R_DrawModels\n");
4111 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]);
4112 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);
4113 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);
4116 if (ent->model && ent->model->Draw != NULL)
4117 ent->model->Draw(ent);
4123 static void R_DrawModelsDepth(void)
4126 entity_render_t *ent;
4128 for (i = 0;i < r_refdef.scene.numentities;i++)
4130 if (!r_refdef.viewcache.entityvisible[i])
4132 ent = r_refdef.scene.entities[i];
4133 if (ent->model && ent->model->DrawDepth != NULL)
4134 ent->model->DrawDepth(ent);
4138 static void R_DrawModelsDebug(void)
4141 entity_render_t *ent;
4143 for (i = 0;i < r_refdef.scene.numentities;i++)
4145 if (!r_refdef.viewcache.entityvisible[i])
4147 ent = r_refdef.scene.entities[i];
4148 if (ent->model && ent->model->DrawDebug != NULL)
4149 ent->model->DrawDebug(ent);
4153 static void R_DrawModelsAddWaterPlanes(void)
4156 entity_render_t *ent;
4158 for (i = 0;i < r_refdef.scene.numentities;i++)
4160 if (!r_refdef.viewcache.entityvisible[i])
4162 ent = r_refdef.scene.entities[i];
4163 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4164 ent->model->DrawAddWaterPlanes(ent);
4168 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}};
4170 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4172 if (r_hdr_irisadaptation.integer)
4177 vec3_t diffusenormal;
4179 vec_t brightness = 0.0f;
4184 VectorCopy(r_refdef.view.forward, forward);
4185 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4187 p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4188 p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4189 p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4190 R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4191 d = DotProduct(forward, diffusenormal);
4192 brightness += VectorLength(ambient);
4194 brightness += d * VectorLength(diffuse);
4196 brightness *= 1.0f / c;
4197 brightness += 0.00001f; // make sure it's never zero
4198 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4199 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4200 current = r_hdr_irisadaptation_value.value;
4202 current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4203 else if (current > goal)
4204 current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4205 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4206 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4208 else if (r_hdr_irisadaptation_value.value != 1.0f)
4209 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4212 static void R_View_SetFrustum(const int *scissor)
4215 double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4216 vec3_t forward, left, up, origin, v;
4220 // flipped x coordinates (because x points left here)
4221 fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4222 fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4223 // non-flipped y coordinates
4224 fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4225 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4228 // we can't trust r_refdef.view.forward and friends in reflected scenes
4229 Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4232 r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4233 r_refdef.view.frustum[0].normal[1] = 0 - 0;
4234 r_refdef.view.frustum[0].normal[2] = -1 - 0;
4235 r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4236 r_refdef.view.frustum[1].normal[1] = 0 + 0;
4237 r_refdef.view.frustum[1].normal[2] = -1 + 0;
4238 r_refdef.view.frustum[2].normal[0] = 0 - 0;
4239 r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4240 r_refdef.view.frustum[2].normal[2] = -1 - 0;
4241 r_refdef.view.frustum[3].normal[0] = 0 + 0;
4242 r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4243 r_refdef.view.frustum[3].normal[2] = -1 + 0;
4247 zNear = r_refdef.nearclip;
4248 nudge = 1.0 - 1.0 / (1<<23);
4249 r_refdef.view.frustum[4].normal[0] = 0 - 0;
4250 r_refdef.view.frustum[4].normal[1] = 0 - 0;
4251 r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4252 r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4253 r_refdef.view.frustum[5].normal[0] = 0 + 0;
4254 r_refdef.view.frustum[5].normal[1] = 0 + 0;
4255 r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4256 r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4262 r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4263 r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4264 r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4265 r_refdef.view.frustum[0].dist = m[15] - m[12];
4267 r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4268 r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4269 r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4270 r_refdef.view.frustum[1].dist = m[15] + m[12];
4272 r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4273 r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4274 r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4275 r_refdef.view.frustum[2].dist = m[15] - m[13];
4277 r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4278 r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4279 r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4280 r_refdef.view.frustum[3].dist = m[15] + m[13];
4282 r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4283 r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4284 r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4285 r_refdef.view.frustum[4].dist = m[15] - m[14];
4287 r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4288 r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4289 r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4290 r_refdef.view.frustum[5].dist = m[15] + m[14];
4293 if (r_refdef.view.useperspective)
4295 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4296 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]);
4297 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]);
4298 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]);
4299 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]);
4301 // then the normals from the corners relative to origin
4302 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4303 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4304 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4305 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4307 // in a NORMAL view, forward cross left == up
4308 // in a REFLECTED view, forward cross left == down
4309 // so our cross products above need to be adjusted for a left handed coordinate system
4310 CrossProduct(forward, left, v);
4311 if(DotProduct(v, up) < 0)
4313 VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4314 VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4315 VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4316 VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4319 // Leaving those out was a mistake, those were in the old code, and they
4320 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4321 // I couldn't reproduce it after adding those normalizations. --blub
4322 VectorNormalize(r_refdef.view.frustum[0].normal);
4323 VectorNormalize(r_refdef.view.frustum[1].normal);
4324 VectorNormalize(r_refdef.view.frustum[2].normal);
4325 VectorNormalize(r_refdef.view.frustum[3].normal);
4327 // make the corners absolute
4328 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4329 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4330 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4331 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4334 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4336 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4337 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4338 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4339 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4340 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4344 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4345 VectorScale(left, 1.0f, r_refdef.view.frustum[1].normal);
4346 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4347 VectorScale(up, 1.0f, r_refdef.view.frustum[3].normal);
4348 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4349 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4350 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4351 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4352 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4353 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4355 r_refdef.view.numfrustumplanes = 5;
4357 if (r_refdef.view.useclipplane)
4359 r_refdef.view.numfrustumplanes = 6;
4360 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4363 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4364 PlaneClassify(r_refdef.view.frustum + i);
4366 // LordHavoc: note to all quake engine coders, Quake had a special case
4367 // for 90 degrees which assumed a square view (wrong), so I removed it,
4368 // Quake2 has it disabled as well.
4370 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4371 //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4372 //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4373 //PlaneClassify(&frustum[0]);
4375 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4376 //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4377 //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4378 //PlaneClassify(&frustum[1]);
4380 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4381 //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4382 //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4383 //PlaneClassify(&frustum[2]);
4385 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4386 //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4387 //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4388 //PlaneClassify(&frustum[3]);
4391 //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4392 //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4393 //PlaneClassify(&frustum[4]);
4396 static void R_View_UpdateWithScissor(const int *myscissor)
4398 R_Main_ResizeViewCache();
4399 R_View_SetFrustum(myscissor);
4400 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4401 R_View_UpdateEntityVisible();
4404 static void R_View_Update(void)
4406 R_Main_ResizeViewCache();
4407 R_View_SetFrustum(NULL);
4408 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4409 R_View_UpdateEntityVisible();
4412 float viewscalefpsadjusted = 1.0f;
4414 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4416 float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4417 scale = bound(0.03125f, scale, 1.0f);
4418 *outwidth = (int)ceil(width * scale);
4419 *outheight = (int)ceil(height * scale);
4422 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4424 const float *customclipplane = NULL;
4426 int /*rtwidth,*/ rtheight;
4427 if (r_refdef.view.useclipplane && allowwaterclippingplane)
4429 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4430 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4431 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4432 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4433 dist = r_refdef.view.clipplane.dist;
4434 plane[0] = r_refdef.view.clipplane.normal[0];
4435 plane[1] = r_refdef.view.clipplane.normal[1];
4436 plane[2] = r_refdef.view.clipplane.normal[2];
4438 customclipplane = plane;
4441 //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4442 rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4444 if (!r_refdef.view.useperspective)
4445 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);
4446 else if (vid.stencil && r_useinfinitefarclip.integer)
4447 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);
4449 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);
4450 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4451 R_SetViewport(&r_refdef.view.viewport);
4454 void R_EntityMatrix(const matrix4x4_t *matrix)
4456 if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4458 gl_modelmatrixchanged = false;
4459 gl_modelmatrix = *matrix;
4460 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4461 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4462 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4463 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4465 switch(vid.renderpath)
4467 case RENDERPATH_GL32:
4468 case RENDERPATH_GLES2:
4469 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4470 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4476 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4478 r_viewport_t viewport;
4482 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4483 R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4484 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4485 R_SetViewport(&viewport);
4486 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4487 GL_Color(1, 1, 1, 1);
4488 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4489 GL_BlendFunc(GL_ONE, GL_ZERO);
4490 GL_ScissorTest(false);
4491 GL_DepthMask(false);
4492 GL_DepthRange(0, 1);
4493 GL_DepthTest(false);
4494 GL_DepthFunc(GL_LEQUAL);
4495 R_EntityMatrix(&identitymatrix);
4496 R_Mesh_ResetTextureState();
4497 GL_PolygonOffset(0, 0);
4498 switch(vid.renderpath)
4500 case RENDERPATH_GL32:
4501 case RENDERPATH_GLES2:
4502 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4505 GL_CullFace(GL_NONE);
4510 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4512 R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4515 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4517 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4518 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4519 GL_Color(1, 1, 1, 1);
4520 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4521 GL_BlendFunc(GL_ONE, GL_ZERO);
4522 GL_ScissorTest(true);
4524 GL_DepthRange(0, 1);
4526 GL_DepthFunc(GL_LEQUAL);
4527 R_EntityMatrix(&identitymatrix);
4528 R_Mesh_ResetTextureState();
4529 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4530 switch(vid.renderpath)
4532 case RENDERPATH_GL32:
4533 case RENDERPATH_GLES2:
4534 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4537 GL_CullFace(r_refdef.view.cullface_back);
4542 R_RenderView_UpdateViewVectors
4545 void R_RenderView_UpdateViewVectors(void)
4547 // break apart the view matrix into vectors for various purposes
4548 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4549 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4550 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4551 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4552 // make an inverted copy of the view matrix for tracking sprites
4553 Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4556 void R_RenderTarget_FreeUnused(qboolean force)
4559 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4560 for (i = 0; i < end; i++)
4562 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4563 // free resources for rendertargets that have not been used for a while
4564 // (note: this check is run after the frame render, so any targets used
4565 // this frame will not be affected even at low framerates)
4566 if (r && (realtime - r->lastusetime > 0.2 || force))
4569 R_Mesh_DestroyFramebufferObject(r->fbo);
4570 for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4571 if (r->colortexture[j])
4572 R_FreeTexture(r->colortexture[j]);
4573 if (r->depthtexture)
4574 R_FreeTexture(r->depthtexture);
4575 Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4580 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4582 float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4586 y2 = (th - y - h) * ih;
4597 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)
4600 r_rendertarget_t *r = NULL;
4602 // first try to reuse an existing slot if possible
4603 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4604 for (i = 0; i < end; i++)
4606 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4607 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)
4612 // no unused exact match found, so we have to make one in the first unused slot
4613 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4614 r->texturewidth = texturewidth;
4615 r->textureheight = textureheight;
4616 r->colortextype[0] = colortextype0;
4617 r->colortextype[1] = colortextype1;
4618 r->colortextype[2] = colortextype2;
4619 r->colortextype[3] = colortextype3;
4620 r->depthtextype = depthtextype;
4621 r->depthisrenderbuffer = depthisrenderbuffer;
4622 for (j = 0; j < 4; j++)
4623 if (r->colortextype[j])
4624 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);
4625 if (r->depthtextype)
4627 if (r->depthisrenderbuffer)
4628 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);
4630 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);
4632 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4634 r_refdef.stats[r_stat_rendertargets_used]++;
4635 r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4636 r->lastusetime = realtime;
4637 R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4641 static void R_Water_StartFrame(void)
4643 int waterwidth, waterheight;
4645 if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4648 // set waterwidth and waterheight to the water resolution that will be
4649 // used (often less than the screen resolution for faster rendering)
4650 waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4651 waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4652 R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4654 if (!r_water.integer || r_showsurfaces.integer)
4655 waterwidth = waterheight = 0;
4657 // set up variables that will be used in shader setup
4658 r_fb.water.waterwidth = waterwidth;
4659 r_fb.water.waterheight = waterheight;
4660 r_fb.water.texturewidth = waterwidth;
4661 r_fb.water.textureheight = waterheight;
4662 r_fb.water.camerawidth = waterwidth;
4663 r_fb.water.cameraheight = waterheight;
4664 r_fb.water.screenscale[0] = 0.5f;
4665 r_fb.water.screenscale[1] = 0.5f;
4666 r_fb.water.screencenter[0] = 0.5f;
4667 r_fb.water.screencenter[1] = 0.5f;
4668 r_fb.water.enabled = waterwidth != 0;
4670 r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4671 r_fb.water.numwaterplanes = 0;
4674 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4676 int planeindex, bestplaneindex, vertexindex;
4677 vec3_t mins, maxs, normal, center, v, n;
4678 vec_t planescore, bestplanescore;
4680 r_waterstate_waterplane_t *p;
4681 texture_t *t = R_GetCurrentTexture(surface->texture);
4683 rsurface.texture = t;
4684 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4685 // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4686 if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4688 // average the vertex normals, find the surface bounds (after deformvertexes)
4689 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4690 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4691 VectorCopy(n, normal);
4692 VectorCopy(v, mins);
4693 VectorCopy(v, maxs);
4694 for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4696 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4697 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4698 VectorAdd(normal, n, normal);
4699 mins[0] = min(mins[0], v[0]);
4700 mins[1] = min(mins[1], v[1]);
4701 mins[2] = min(mins[2], v[2]);
4702 maxs[0] = max(maxs[0], v[0]);
4703 maxs[1] = max(maxs[1], v[1]);
4704 maxs[2] = max(maxs[2], v[2]);
4706 VectorNormalize(normal);
4707 VectorMAM(0.5f, mins, 0.5f, maxs, center);
4709 VectorCopy(normal, plane.normal);
4710 VectorNormalize(plane.normal);
4711 plane.dist = DotProduct(center, plane.normal);
4712 PlaneClassify(&plane);
4713 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4715 // skip backfaces (except if nocullface is set)
4716 // if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4718 VectorNegate(plane.normal, plane.normal);
4720 PlaneClassify(&plane);
4724 // find a matching plane if there is one
4725 bestplaneindex = -1;
4726 bestplanescore = 1048576.0f;
4727 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4729 if(p->camera_entity == t->camera_entity)
4731 planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4732 if (bestplaneindex < 0 || bestplanescore > planescore)
4734 bestplaneindex = planeindex;
4735 bestplanescore = planescore;
4739 planeindex = bestplaneindex;
4741 // if this surface does not fit any known plane rendered this frame, add one
4742 if (planeindex < 0 || bestplanescore > 0.001f)
4744 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4746 // store the new plane
4747 planeindex = r_fb.water.numwaterplanes++;
4748 p = r_fb.water.waterplanes + planeindex;
4750 // clear materialflags and pvs
4751 p->materialflags = 0;
4752 p->pvsvalid = false;
4753 p->camera_entity = t->camera_entity;
4754 VectorCopy(mins, p->mins);
4755 VectorCopy(maxs, p->maxs);
4759 // We're totally screwed.
4765 // merge mins/maxs when we're adding this surface to the plane
4766 p = r_fb.water.waterplanes + planeindex;
4767 p->mins[0] = min(p->mins[0], mins[0]);
4768 p->mins[1] = min(p->mins[1], mins[1]);
4769 p->mins[2] = min(p->mins[2], mins[2]);
4770 p->maxs[0] = max(p->maxs[0], maxs[0]);
4771 p->maxs[1] = max(p->maxs[1], maxs[1]);
4772 p->maxs[2] = max(p->maxs[2], maxs[2]);
4774 // merge this surface's materialflags into the waterplane
4775 p->materialflags |= t->currentmaterialflags;
4776 if(!(p->materialflags & MATERIALFLAG_CAMERA))
4778 // merge this surface's PVS into the waterplane
4779 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4780 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4782 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4788 extern cvar_t r_drawparticles;
4789 extern cvar_t r_drawdecals;
4791 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4794 r_refdef_view_t originalview;
4795 r_refdef_view_t myview;
4796 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;
4797 r_waterstate_waterplane_t *p;
4799 r_rendertarget_t *rt;
4801 originalview = r_refdef.view;
4803 // lowquality hack, temporarily shut down some cvars and restore afterwards
4804 qualityreduction = r_water_lowquality.integer;
4805 if (qualityreduction > 0)
4807 if (qualityreduction >= 1)
4809 old_r_shadows = r_shadows.integer;
4810 old_r_worldrtlight = r_shadow_realtime_world.integer;
4811 old_r_dlight = r_shadow_realtime_dlight.integer;
4812 Cvar_SetValueQuick(&r_shadows, 0);
4813 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4814 Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4816 if (qualityreduction >= 2)
4818 old_r_dynamic = r_dynamic.integer;
4819 old_r_particles = r_drawparticles.integer;
4820 old_r_decals = r_drawdecals.integer;
4821 Cvar_SetValueQuick(&r_dynamic, 0);
4822 Cvar_SetValueQuick(&r_drawparticles, 0);
4823 Cvar_SetValueQuick(&r_drawdecals, 0);
4827 for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4829 p->rt_reflection = NULL;
4830 p->rt_refraction = NULL;
4831 p->rt_camera = NULL;
4835 r_refdef.view = originalview;
4836 r_refdef.view.showdebug = false;
4837 r_refdef.view.width = r_fb.water.waterwidth;
4838 r_refdef.view.height = r_fb.water.waterheight;
4839 r_refdef.view.useclipplane = true;
4840 myview = r_refdef.view;
4841 r_fb.water.renderingscene = true;
4842 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4844 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4847 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4849 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);
4850 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4852 r_refdef.view = myview;
4853 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4854 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4855 if(r_water_scissormode.integer)
4857 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4858 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4860 p->rt_reflection = NULL;
4861 p->rt_refraction = NULL;
4862 p->rt_camera = NULL;
4867 r_refdef.view.clipplane = p->plane;
4868 // reflected view origin may be in solid, so don't cull with it
4869 r_refdef.view.usevieworiginculling = false;
4870 // reverse the cullface settings for this render
4871 r_refdef.view.cullface_front = GL_FRONT;
4872 r_refdef.view.cullface_back = GL_BACK;
4873 // combined pvs (based on what can be seen from each surface center)
4874 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4876 r_refdef.view.usecustompvs = true;
4878 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4880 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4883 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4884 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4885 GL_ScissorTest(false);
4886 R_ClearScreen(r_refdef.fogenabled);
4887 GL_ScissorTest(true);
4888 if(r_water_scissormode.integer & 2)
4889 R_View_UpdateWithScissor(myscissor);
4892 R_AnimCache_CacheVisibleEntities();
4893 if(r_water_scissormode.integer & 1)
4894 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4895 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4897 r_fb.water.hideplayer = false;
4898 p->rt_reflection = rt;
4901 // render the normal view scene and copy into texture
4902 // (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)
4903 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4905 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);
4906 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4908 r_refdef.view = myview;
4909 if(r_water_scissormode.integer)
4911 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4912 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4914 p->rt_reflection = NULL;
4915 p->rt_refraction = NULL;
4916 p->rt_camera = NULL;
4921 // combined pvs (based on what can be seen from each surface center)
4922 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4924 r_refdef.view.usecustompvs = true;
4926 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4928 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4931 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4933 r_refdef.view.clipplane = p->plane;
4934 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4935 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4937 if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4939 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4940 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4941 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4942 R_RenderView_UpdateViewVectors();
4943 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4945 r_refdef.view.usecustompvs = true;
4946 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);
4950 PlaneClassify(&r_refdef.view.clipplane);
4952 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4953 GL_ScissorTest(false);
4954 R_ClearScreen(r_refdef.fogenabled);
4955 GL_ScissorTest(true);
4956 if(r_water_scissormode.integer & 2)
4957 R_View_UpdateWithScissor(myscissor);
4960 R_AnimCache_CacheVisibleEntities();
4961 if(r_water_scissormode.integer & 1)
4962 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4963 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4965 r_fb.water.hideplayer = false;
4966 p->rt_refraction = rt;
4968 else if (p->materialflags & MATERIALFLAG_CAMERA)
4970 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);
4971 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4973 r_refdef.view = myview;
4975 r_refdef.view.clipplane = p->plane;
4976 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4977 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4979 r_refdef.view.width = r_fb.water.camerawidth;
4980 r_refdef.view.height = r_fb.water.cameraheight;
4981 r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4982 r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4983 r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4984 r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4986 if(p->camera_entity)
4988 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4989 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4992 // note: all of the view is used for displaying... so
4993 // there is no use in scissoring
4995 // reverse the cullface settings for this render
4996 r_refdef.view.cullface_front = GL_FRONT;
4997 r_refdef.view.cullface_back = GL_BACK;
4998 // also reverse the view matrix
4999 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
5000 R_RenderView_UpdateViewVectors();
5001 if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5003 r_refdef.view.usecustompvs = true;
5004 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);
5007 // camera needs no clipplane
5008 r_refdef.view.useclipplane = false;
5009 // TODO: is the camera origin always valid? if so we don't need to clear this
5010 r_refdef.view.usevieworiginculling = false;
5012 PlaneClassify(&r_refdef.view.clipplane);
5014 r_fb.water.hideplayer = false;
5016 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5017 GL_ScissorTest(false);
5018 R_ClearScreen(r_refdef.fogenabled);
5019 GL_ScissorTest(true);
5021 R_AnimCache_CacheVisibleEntities();
5022 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5024 r_fb.water.hideplayer = false;
5029 r_fb.water.renderingscene = false;
5030 r_refdef.view = originalview;
5031 R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5033 R_AnimCache_CacheVisibleEntities();
5036 r_refdef.view = originalview;
5037 r_fb.water.renderingscene = false;
5038 Cvar_SetValueQuick(&r_water, 0);
5039 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
5041 // lowquality hack, restore cvars
5042 if (qualityreduction > 0)
5044 if (qualityreduction >= 1)
5046 Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5047 Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5048 Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5050 if (qualityreduction >= 2)
5052 Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5053 Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5054 Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5059 static void R_Bloom_StartFrame(void)
5061 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5062 int viewwidth, viewheight;
5063 textype_t textype = TEXTYPE_COLORBUFFER;
5065 // clear the pointers to rendertargets from last frame as they're stale
5066 r_fb.rt_screen = NULL;
5067 r_fb.rt_bloom = NULL;
5069 switch (vid.renderpath)
5071 case RENDERPATH_GL32:
5072 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5073 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5074 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5076 case RENDERPATH_GLES2:
5077 r_fb.usedepthtextures = false;
5081 if (r_viewscale_fpsscaling.integer)
5083 double actualframetime;
5084 double targetframetime;
5086 actualframetime = r_refdef.lastdrawscreentime;
5087 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5088 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5089 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5090 if (r_viewscale_fpsscaling_stepsize.value > 0)
5091 adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5092 viewscalefpsadjusted += adjust;
5093 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5096 viewscalefpsadjusted = 1.0f;
5098 R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5100 // set bloomwidth and bloomheight to the bloom resolution that will be
5101 // used (often less than the screen resolution for faster rendering)
5102 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5103 r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5104 r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5105 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5106 r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5108 // calculate desired texture sizes
5109 screentexturewidth = viewwidth;
5110 screentextureheight = viewheight;
5111 bloomtexturewidth = r_fb.bloomwidth;
5112 bloomtextureheight = r_fb.bloomheight;
5114 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))
5116 Cvar_SetValueQuick(&r_bloom, 0);
5117 Cvar_SetValueQuick(&r_motionblur, 0);
5118 Cvar_SetValueQuick(&r_damageblur, 0);
5121 // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5122 if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5124 if (r_fb.ghosttexture)
5125 R_FreeTexture(r_fb.ghosttexture);
5126 r_fb.ghosttexture = NULL;
5128 r_fb.screentexturewidth = screentexturewidth;
5129 r_fb.screentextureheight = screentextureheight;
5130 r_fb.textype = textype;
5132 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5134 if (r_motionblur.value > 0 || r_damageblur.value > 0)
5135 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);
5136 r_fb.ghosttexture_valid = false;
5140 if (r_bloom.integer)
5142 // bloom texture is a different resolution
5143 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5144 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5145 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5148 r_fb.bloomwidth = r_fb.bloomheight = 0;
5150 r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5152 r_refdef.view.clear = true;
5155 static void R_Bloom_MakeTexture(void)
5158 float xoffset, yoffset, r, brighten;
5159 float colorscale = r_bloom_colorscale.value;
5160 r_viewport_t bloomviewport;
5161 r_rendertarget_t *prev, *cur;
5162 textype_t textype = r_fb.rt_screen->colortextype[0];
5164 r_refdef.stats[r_stat_bloom]++;
5166 R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5168 // scale down screen texture to the bloom texture size
5170 prev = r_fb.rt_screen;
5171 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5172 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5173 R_SetViewport(&bloomviewport);
5174 GL_CullFace(GL_NONE);
5175 GL_DepthTest(false);
5176 GL_BlendFunc(GL_ONE, GL_ZERO);
5177 GL_Color(colorscale, colorscale, colorscale, 1);
5178 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5179 // TODO: do boxfilter scale-down in shader?
5180 R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5181 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5182 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5183 // we now have a properly scaled bloom image
5185 // multiply bloom image by itself as many times as desired to darken it
5186 // TODO: if people actually use this it could be done more quickly in the previous shader pass
5187 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5190 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5191 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5193 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5195 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5196 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5197 GL_Color(1,1,1,1); // no fix factor supported here
5198 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5199 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5200 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5201 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5205 range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5206 brighten = r_bloom_brighten.value;
5207 brighten = sqrt(brighten);
5209 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5211 for (dir = 0;dir < 2;dir++)
5214 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5215 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5216 // blend on at multiple vertical offsets to achieve a vertical blur
5217 // TODO: do offset blends using GLSL
5218 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5220 GL_BlendFunc(GL_ONE, GL_ZERO);
5222 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5224 for (x = -range;x <= range;x++)
5226 if (!dir){xoffset = 0;yoffset = x;}
5227 else {xoffset = x;yoffset = 0;}
5228 xoffset /= (float)prev->texturewidth;
5229 yoffset /= (float)prev->textureheight;
5230 // compute a texcoord array with the specified x and y offset
5231 r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5232 r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5233 r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5234 r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5235 r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5236 r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5237 r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5238 r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5239 // this r value looks like a 'dot' particle, fading sharply to
5240 // black at the edges
5241 // (probably not realistic but looks good enough)
5242 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5243 //r = brighten/(range*2+1);
5244 r = brighten / (range * 2 + 1);
5246 r *= (1 - x*x/(float)((range+1)*(range+1)));
5250 GL_Color(r, r, r, 1);
5252 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5254 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5255 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5257 GL_BlendFunc(GL_ONE, GL_ONE);
5262 // now we have the bloom image, so keep track of it
5263 r_fb.rt_bloom = cur;
5266 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5268 dpuint64 permutation;
5269 float uservecs[4][4];
5270 rtexture_t *viewtexture;
5271 rtexture_t *bloomtexture;
5273 R_EntityMatrix(&identitymatrix);
5275 if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5277 // declare variables
5278 float blur_factor, blur_mouseaccel, blur_velocity;
5279 static float blur_average;
5280 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5282 // set a goal for the factoring
5283 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5284 / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5285 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5286 / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5287 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5288 + (blur_mouseaccel * r_motionblur_mousefactor.value));
5290 // from the goal, pick an averaged value between goal and last value
5291 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5292 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5294 // enforce minimum amount of blur
5295 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5297 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5299 // calculate values into a standard alpha
5300 cl.motionbluralpha = 1 - exp(-
5302 (r_motionblur.value * blur_factor / 80)
5304 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5307 max(0.0001, cl.time - cl.oldtime) // fps independent
5310 // randomization for the blur value to combat persistent ghosting
5311 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5312 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5315 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5316 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5318 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5319 GL_Color(1, 1, 1, cl.motionbluralpha);
5320 R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5321 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5322 R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5323 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5324 r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5327 // updates old view angles for next pass
5328 VectorCopy(cl.viewangles, blur_oldangles);
5330 // copy view into the ghost texture
5331 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5332 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5333 r_fb.ghosttexture_valid = true;
5336 if (r_fb.bloomwidth)
5338 // make the bloom texture
5339 R_Bloom_MakeTexture();
5342 #if _MSC_VER >= 1400
5343 #define sscanf sscanf_s
5345 memset(uservecs, 0, sizeof(uservecs));
5346 if (r_glsl_postprocess_uservec1_enable.integer)
5347 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5348 if (r_glsl_postprocess_uservec2_enable.integer)
5349 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5350 if (r_glsl_postprocess_uservec3_enable.integer)
5351 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5352 if (r_glsl_postprocess_uservec4_enable.integer)
5353 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5355 // render to the screen fbo
5356 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5357 GL_Color(1, 1, 1, 1);
5358 GL_BlendFunc(GL_ONE, GL_ZERO);
5360 viewtexture = r_fb.rt_screen->colortexture[0];
5361 bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5363 if (r_rendertarget_debug.integer >= 0)
5365 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5366 if (rt && rt->colortexture[0])
5368 viewtexture = rt->colortexture[0];
5369 bloomtexture = NULL;
5373 R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5374 switch(vid.renderpath)
5376 case RENDERPATH_GL32:
5377 case RENDERPATH_GLES2:
5379 (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5380 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5381 | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5382 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5383 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5384 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5385 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , viewtexture);
5386 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , bloomtexture);
5387 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps );
5388 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]);
5389 if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5390 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]);
5391 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]);
5392 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]);
5393 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]);
5394 if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value);
5395 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5396 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);
5399 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5400 r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5403 matrix4x4_t r_waterscrollmatrix;
5405 void R_UpdateFog(void)
5408 if (gamemode == GAME_NEHAHRA)
5410 if (gl_fogenable.integer)
5412 r_refdef.oldgl_fogenable = true;
5413 r_refdef.fog_density = gl_fogdensity.value;
5414 r_refdef.fog_red = gl_fogred.value;
5415 r_refdef.fog_green = gl_foggreen.value;
5416 r_refdef.fog_blue = gl_fogblue.value;
5417 r_refdef.fog_alpha = 1;
5418 r_refdef.fog_start = 0;
5419 r_refdef.fog_end = gl_skyclip.value;
5420 r_refdef.fog_height = 1<<30;
5421 r_refdef.fog_fadedepth = 128;
5423 else if (r_refdef.oldgl_fogenable)
5425 r_refdef.oldgl_fogenable = false;
5426 r_refdef.fog_density = 0;
5427 r_refdef.fog_red = 0;
5428 r_refdef.fog_green = 0;
5429 r_refdef.fog_blue = 0;
5430 r_refdef.fog_alpha = 0;
5431 r_refdef.fog_start = 0;
5432 r_refdef.fog_end = 0;
5433 r_refdef.fog_height = 1<<30;
5434 r_refdef.fog_fadedepth = 128;
5439 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5440 r_refdef.fog_start = max(0, r_refdef.fog_start);
5441 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5443 if (r_refdef.fog_density && r_drawfog.integer)
5445 r_refdef.fogenabled = true;
5446 // this is the point where the fog reaches 0.9986 alpha, which we
5447 // consider a good enough cutoff point for the texture
5448 // (0.9986 * 256 == 255.6)
5449 if (r_fog_exp2.integer)
5450 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5452 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5453 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5454 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5455 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5456 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5457 R_BuildFogHeightTexture();
5458 // fog color was already set
5459 // update the fog texture
5460 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)
5461 R_BuildFogTexture();
5462 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5463 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5466 r_refdef.fogenabled = false;
5469 if (r_refdef.fog_density)
5471 r_refdef.fogcolor[0] = r_refdef.fog_red;
5472 r_refdef.fogcolor[1] = r_refdef.fog_green;
5473 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5475 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5476 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5477 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5478 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5482 VectorCopy(r_refdef.fogcolor, fogvec);
5483 // color.rgb *= ContrastBoost * SceneBrightness;
5484 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5485 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5486 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5487 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5492 void R_UpdateVariables(void)
5496 r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5498 r_refdef.farclip = r_farclip_base.value;
5499 if (r_refdef.scene.worldmodel)
5500 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5501 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5503 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5504 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5505 r_refdef.polygonfactor = 0;
5506 r_refdef.polygonoffset = 0;
5508 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5509 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5510 r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5511 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5512 r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5513 if (FAKELIGHT_ENABLED)
5515 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5517 else if (r_refdef.scene.worldmodel)
5519 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5521 if (r_showsurfaces.integer)
5523 r_refdef.scene.rtworld = false;
5524 r_refdef.scene.rtworldshadows = false;
5525 r_refdef.scene.rtdlight = false;
5526 r_refdef.scene.rtdlightshadows = false;
5527 r_refdef.scene.lightmapintensity = 0;
5530 r_gpuskeletal = false;
5531 switch(vid.renderpath)
5533 case RENDERPATH_GL32:
5534 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5535 case RENDERPATH_GLES2:
5536 if(!vid_gammatables_trivial)
5538 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5540 // build GLSL gamma texture
5541 #define RAMPWIDTH 256
5542 unsigned short ramp[RAMPWIDTH * 3];
5543 unsigned char rampbgr[RAMPWIDTH][4];
5546 r_texture_gammaramps_serial = vid_gammatables_serial;
5548 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5549 for(i = 0; i < RAMPWIDTH; ++i)
5551 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5552 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5553 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5556 if (r_texture_gammaramps)
5558 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5562 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5568 // remove GLSL gamma texture
5574 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5575 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5581 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5582 if( scenetype != r_currentscenetype ) {
5583 // store the old scenetype
5584 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5585 r_currentscenetype = scenetype;
5586 // move in the new scene
5587 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5596 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5598 // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5599 if( scenetype == r_currentscenetype ) {
5600 return &r_refdef.scene;
5602 return &r_scenes_store[ scenetype ];
5606 static int R_SortEntities_Compare(const void *ap, const void *bp)
5608 const entity_render_t *a = *(const entity_render_t **)ap;
5609 const entity_render_t *b = *(const entity_render_t **)bp;
5612 if(a->model < b->model)
5614 if(a->model > b->model)
5618 // TODO possibly calculate the REAL skinnum here first using
5620 if(a->skinnum < b->skinnum)
5622 if(a->skinnum > b->skinnum)
5625 // everything we compared is equal
5628 static void R_SortEntities(void)
5630 // below or equal 2 ents, sorting never gains anything
5631 if(r_refdef.scene.numentities <= 2)
5634 qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5642 extern cvar_t r_shadow_bouncegrid;
5643 extern cvar_t v_isometric;
5644 extern void V_MakeViewIsometric(void);
5645 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5647 matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5649 rtexture_t *viewdepthtexture = NULL;
5650 rtexture_t *viewcolortexture = NULL;
5651 int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5653 // finish any 2D rendering that was queued
5656 if (r_timereport_active)
5657 R_TimeReport("start");
5658 r_textureframe++; // used only by R_GetCurrentTexture
5659 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5661 if(R_CompileShader_CheckStaticParms())
5664 if (!r_drawentities.integer)
5665 r_refdef.scene.numentities = 0;
5666 else if (r_sortentities.integer)
5669 R_AnimCache_ClearCache();
5671 /* adjust for stereo display */
5672 if(R_Stereo_Active())
5674 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);
5675 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5678 if (r_refdef.view.isoverlay)
5680 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5681 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5682 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5683 R_TimeReport("depthclear");
5685 r_refdef.view.showdebug = false;
5687 r_fb.water.enabled = false;
5688 r_fb.water.numwaterplanes = 0;
5690 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5692 r_refdef.view.matrix = originalmatrix;
5698 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5700 r_refdef.view.matrix = originalmatrix;
5704 r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5705 if (v_isometric.integer && r_refdef.view.ismain)
5706 V_MakeViewIsometric();
5708 r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5710 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5711 // in sRGB fallback, behave similar to true sRGB: convert this
5712 // value from linear to sRGB
5713 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5715 R_RenderView_UpdateViewVectors();
5717 R_Shadow_UpdateWorldLightSelection();
5719 // this will set up r_fb.rt_screen
5720 R_Bloom_StartFrame();
5722 // apply bloom brightness offset
5724 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5726 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5729 viewfbo = r_fb.rt_screen->fbo;
5730 viewdepthtexture = r_fb.rt_screen->depthtexture;
5731 viewcolortexture = r_fb.rt_screen->colortexture[0];
5735 viewheight = height;
5738 R_Water_StartFrame();
5741 if (r_timereport_active)
5742 R_TimeReport("viewsetup");
5744 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5746 // clear the whole fbo every frame - otherwise the driver will consider
5747 // it to be an inter-frame texture and stall in multi-gpu configurations
5749 GL_ScissorTest(false);
5750 R_ClearScreen(r_refdef.fogenabled);
5751 if (r_timereport_active)
5752 R_TimeReport("viewclear");
5754 r_refdef.view.clear = true;
5756 r_refdef.view.showdebug = true;
5759 if (r_timereport_active)
5760 R_TimeReport("visibility");
5762 R_AnimCache_CacheVisibleEntities();
5763 if (r_timereport_active)
5764 R_TimeReport("animcache");
5766 R_Shadow_UpdateBounceGridTexture();
5767 if (r_timereport_active && r_shadow_bouncegrid.integer)
5768 R_TimeReport("bouncegrid");
5770 r_fb.water.numwaterplanes = 0;
5771 if (r_fb.water.enabled)
5772 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5774 // for the actual view render we use scissoring a fair amount, so scissor
5775 // test needs to be on
5777 GL_ScissorTest(true);
5778 GL_Scissor(viewx, viewy, viewwidth, viewheight);
5779 R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5780 r_fb.water.numwaterplanes = 0;
5782 // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5783 GL_ScissorTest(false);
5785 R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5786 if (r_timereport_active)
5787 R_TimeReport("blendview");
5789 r_refdef.view.matrix = originalmatrix;
5793 // go back to 2d rendering
5797 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5799 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5801 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5802 if (r_timereport_active)
5803 R_TimeReport("waterworld");
5806 // don't let sound skip if going slow
5807 if (r_refdef.scene.extraupdate)
5810 R_DrawModelsAddWaterPlanes();
5811 if (r_timereport_active)
5812 R_TimeReport("watermodels");
5814 if (r_fb.water.numwaterplanes)
5816 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5817 if (r_timereport_active)
5818 R_TimeReport("waterscenes");
5822 extern cvar_t cl_locs_show;
5823 static void R_DrawLocs(void);
5824 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5825 static void R_DrawModelDecals(void);
5826 extern cvar_t cl_decals_newsystem;
5827 extern qboolean r_shadow_usingdeferredprepass;
5828 extern int r_shadow_shadowmapatlas_modelshadows_size;
5829 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5831 qboolean shadowmapping = false;
5833 if (r_timereport_active)
5834 R_TimeReport("beginscene");
5836 r_refdef.stats[r_stat_renders]++;
5840 // don't let sound skip if going slow
5841 if (r_refdef.scene.extraupdate)
5844 R_MeshQueue_BeginScene();
5848 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);
5850 if (r_timereport_active)
5851 R_TimeReport("skystartframe");
5853 if (cl.csqc_vidvars.drawworld)
5855 // don't let sound skip if going slow
5856 if (r_refdef.scene.extraupdate)
5859 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5861 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5862 if (r_timereport_active)
5863 R_TimeReport("worldsky");
5866 if (R_DrawBrushModelsSky() && r_timereport_active)
5867 R_TimeReport("bmodelsky");
5869 if (skyrendermasked && skyrenderlater)
5871 // we have to force off the water clipping plane while rendering sky
5872 R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5874 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5875 if (r_timereport_active)
5876 R_TimeReport("sky");
5880 // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5881 r_shadow_viewfbo = viewfbo;
5882 r_shadow_viewdepthtexture = viewdepthtexture;
5883 r_shadow_viewcolortexture = viewcolortexture;
5884 r_shadow_viewx = viewx;
5885 r_shadow_viewy = viewy;
5886 r_shadow_viewwidth = viewwidth;
5887 r_shadow_viewheight = viewheight;
5889 R_Shadow_PrepareModelShadows();
5890 R_Shadow_PrepareLights();
5891 if (r_timereport_active)
5892 R_TimeReport("preparelights");
5894 // render all the shadowmaps that will be used for this view
5895 shadowmapping = R_Shadow_ShadowMappingEnabled();
5896 if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5898 R_Shadow_DrawShadowMaps();
5899 if (r_timereport_active)
5900 R_TimeReport("shadowmaps");
5903 // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5904 if (r_shadow_usingdeferredprepass)
5905 R_Shadow_DrawPrepass();
5907 // now we begin the forward pass of the view render
5908 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5910 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5911 if (r_timereport_active)
5912 R_TimeReport("worlddepth");
5914 if (r_depthfirst.integer >= 2)
5916 R_DrawModelsDepth();
5917 if (r_timereport_active)
5918 R_TimeReport("modeldepth");
5921 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5923 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5924 if (r_timereport_active)
5925 R_TimeReport("world");
5928 // don't let sound skip if going slow
5929 if (r_refdef.scene.extraupdate)
5933 if (r_timereport_active)
5934 R_TimeReport("models");
5936 // don't let sound skip if going slow
5937 if (r_refdef.scene.extraupdate)
5940 if (!r_shadow_usingdeferredprepass)
5942 R_Shadow_DrawLights();
5943 if (r_timereport_active)
5944 R_TimeReport("rtlights");
5947 // don't let sound skip if going slow
5948 if (r_refdef.scene.extraupdate)
5951 if (cl.csqc_vidvars.drawworld)
5953 if (cl_decals_newsystem.integer)
5955 R_DrawModelDecals();
5956 if (r_timereport_active)
5957 R_TimeReport("modeldecals");
5962 if (r_timereport_active)
5963 R_TimeReport("decals");
5967 if (r_timereport_active)
5968 R_TimeReport("particles");
5971 if (r_timereport_active)
5972 R_TimeReport("explosions");
5975 if (r_refdef.view.showdebug)
5977 if (cl_locs_show.integer)
5980 if (r_timereport_active)
5981 R_TimeReport("showlocs");
5984 if (r_drawportals.integer)
5987 if (r_timereport_active)
5988 R_TimeReport("portals");
5991 if (r_showbboxes_client.value > 0)
5993 R_DrawEntityBBoxes(CLVM_prog);
5994 if (r_timereport_active)
5995 R_TimeReport("clbboxes");
5997 if (r_showbboxes.value > 0)
5999 R_DrawEntityBBoxes(SVVM_prog);
6000 if (r_timereport_active)
6001 R_TimeReport("svbboxes");
6005 if (r_transparent.integer)
6007 R_MeshQueue_RenderTransparent();
6008 if (r_timereport_active)
6009 R_TimeReport("drawtrans");
6012 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))
6014 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6015 if (r_timereport_active)
6016 R_TimeReport("worlddebug");
6017 R_DrawModelsDebug();
6018 if (r_timereport_active)
6019 R_TimeReport("modeldebug");
6022 if (cl.csqc_vidvars.drawworld)
6024 R_Shadow_DrawCoronas();
6025 if (r_timereport_active)
6026 R_TimeReport("coronas");
6029 // don't let sound skip if going slow
6030 if (r_refdef.scene.extraupdate)
6034 static const unsigned short bboxelements[36] =
6044 #define BBOXEDGES 13
6045 static const float bboxedges[BBOXEDGES][6] =
6048 { 0, 0, 0, 1, 1, 1 },
6050 { 0, 0, 0, 0, 1, 0 },
6051 { 0, 0, 0, 1, 0, 0 },
6052 { 0, 1, 0, 1, 1, 0 },
6053 { 1, 0, 0, 1, 1, 0 },
6055 { 0, 0, 1, 0, 1, 1 },
6056 { 0, 0, 1, 1, 0, 1 },
6057 { 0, 1, 1, 1, 1, 1 },
6058 { 1, 0, 1, 1, 1, 1 },
6060 { 0, 0, 0, 0, 0, 1 },
6061 { 1, 0, 0, 1, 0, 1 },
6062 { 0, 1, 0, 0, 1, 1 },
6063 { 1, 1, 0, 1, 1, 1 },
6066 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6068 int numvertices = BBOXEDGES * 8;
6069 float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6070 int numtriangles = BBOXEDGES * 12;
6071 unsigned short elements[BBOXEDGES * 36];
6073 float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6075 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6077 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6078 GL_DepthMask(false);
6079 GL_DepthRange(0, 1);
6080 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6082 for (edge = 0; edge < BBOXEDGES; edge++)
6084 for (i = 0; i < 3; i++)
6086 edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6087 edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6089 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6090 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6091 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6092 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6093 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6094 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6095 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6096 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6097 for (i = 0; i < 36; i++)
6098 elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6100 R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6101 if (r_refdef.fogenabled)
6103 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6105 f1 = RSurf_FogVertex(v);
6107 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6108 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6109 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6112 R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6113 R_Mesh_ResetTextureState();
6114 R_SetupShader_Generic_NoTexture(false, false);
6115 R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6118 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6120 // hacky overloading of the parameters
6121 prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6124 prvm_edict_t *edict;
6126 GL_CullFace(GL_NONE);
6127 R_SetupShader_Generic_NoTexture(false, false);
6129 for (i = 0;i < numsurfaces;i++)
6131 edict = PRVM_EDICT_NUM(surfacelist[i]);
6132 switch ((int)PRVM_serveredictfloat(edict, solid))
6134 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
6135 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
6136 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
6137 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6138 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
6139 case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break;
6140 default: Vector4Set(color, 0, 0, 0, 0.50);break;
6142 if (prog == CLVM_prog)
6143 color[3] *= r_showbboxes_client.value;
6145 color[3] *= r_showbboxes.value;
6146 color[3] = bound(0, color[3], 1);
6147 GL_DepthTest(!r_showdisabledepthtest.integer);
6148 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6152 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6155 prvm_edict_t *edict;
6161 for (i = 0; i < prog->num_edicts; i++)
6163 edict = PRVM_EDICT_NUM(i);
6164 if (edict->priv.server->free)
6166 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6167 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6169 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6171 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6172 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6176 static const int nomodelelement3i[24] =
6188 static const unsigned short nomodelelement3s[24] =
6200 static const float nomodelvertex3f[6*3] =
6210 static const float nomodelcolor4f[6*4] =
6212 0.0f, 0.0f, 0.5f, 1.0f,
6213 0.0f, 0.0f, 0.5f, 1.0f,
6214 0.0f, 0.5f, 0.0f, 1.0f,
6215 0.0f, 0.5f, 0.0f, 1.0f,
6216 0.5f, 0.0f, 0.0f, 1.0f,
6217 0.5f, 0.0f, 0.0f, 1.0f
6220 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6226 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);
6228 // this is only called once per entity so numsurfaces is always 1, and
6229 // surfacelist is always {0}, so this code does not handle batches
6231 if (rsurface.ent_flags & RENDER_ADDITIVE)
6233 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6234 GL_DepthMask(false);
6236 else if (ent->alpha < 1)
6238 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6239 GL_DepthMask(false);
6243 GL_BlendFunc(GL_ONE, GL_ZERO);
6246 GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6247 GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6248 GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6249 GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6250 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6251 for (i = 0, c = color4f;i < 6;i++, c += 4)
6253 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6254 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6255 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6258 if (r_refdef.fogenabled)
6260 for (i = 0, c = color4f;i < 6;i++, c += 4)
6262 f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6264 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6265 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6266 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6269 // R_Mesh_ResetTextureState();
6270 R_SetupShader_Generic_NoTexture(false, false);
6271 R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6272 R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6275 void R_DrawNoModel(entity_render_t *ent)
6278 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6279 if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6280 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6282 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6285 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6287 vec3_t right1, right2, diff, normal;
6289 VectorSubtract (org2, org1, normal);
6291 // calculate 'right' vector for start
6292 VectorSubtract (r_refdef.view.origin, org1, diff);
6293 CrossProduct (normal, diff, right1);
6294 VectorNormalize (right1);
6296 // calculate 'right' vector for end
6297 VectorSubtract (r_refdef.view.origin, org2, diff);
6298 CrossProduct (normal, diff, right2);
6299 VectorNormalize (right2);
6301 vert[ 0] = org1[0] + width * right1[0];
6302 vert[ 1] = org1[1] + width * right1[1];
6303 vert[ 2] = org1[2] + width * right1[2];
6304 vert[ 3] = org1[0] - width * right1[0];
6305 vert[ 4] = org1[1] - width * right1[1];
6306 vert[ 5] = org1[2] - width * right1[2];
6307 vert[ 6] = org2[0] - width * right2[0];
6308 vert[ 7] = org2[1] - width * right2[1];
6309 vert[ 8] = org2[2] - width * right2[2];
6310 vert[ 9] = org2[0] + width * right2[0];
6311 vert[10] = org2[1] + width * right2[1];
6312 vert[11] = org2[2] + width * right2[2];
6315 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)
6317 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6318 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6319 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6320 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6321 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6322 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6323 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6324 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6325 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6326 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6327 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6328 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6331 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6336 VectorSet(v, x, y, z);
6337 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6338 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6340 if (i == mesh->numvertices)
6342 if (mesh->numvertices < mesh->maxvertices)
6344 VectorCopy(v, vertex3f);
6345 mesh->numvertices++;
6347 return mesh->numvertices;
6353 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6357 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6358 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6359 e = mesh->element3i + mesh->numtriangles * 3;
6360 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6362 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6363 if (mesh->numtriangles < mesh->maxtriangles)
6368 mesh->numtriangles++;
6370 element[1] = element[2];
6374 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6378 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6379 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6380 e = mesh->element3i + mesh->numtriangles * 3;
6381 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6383 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6384 if (mesh->numtriangles < mesh->maxtriangles)
6389 mesh->numtriangles++;
6391 element[1] = element[2];
6395 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6396 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6398 int planenum, planenum2;
6401 mplane_t *plane, *plane2;
6403 double temppoints[2][256*3];
6404 // figure out how large a bounding box we need to properly compute this brush
6406 for (w = 0;w < numplanes;w++)
6407 maxdist = max(maxdist, fabs(planes[w].dist));
6408 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6409 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6410 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6414 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6415 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6417 if (planenum2 == planenum)
6419 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);
6422 if (tempnumpoints < 3)
6424 // generate elements forming a triangle fan for this polygon
6425 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6429 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)
6431 texturelayer_t *layer;
6432 layer = t->currentlayers + t->currentnumlayers++;
6434 layer->depthmask = depthmask;
6435 layer->blendfunc1 = blendfunc1;
6436 layer->blendfunc2 = blendfunc2;
6437 layer->texture = texture;
6438 layer->texmatrix = *matrix;
6439 layer->color[0] = r;
6440 layer->color[1] = g;
6441 layer->color[2] = b;
6442 layer->color[3] = a;
6445 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6447 if(parms[0] == 0 && parms[1] == 0)
6449 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6450 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6455 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6458 index = parms[2] + rsurface.shadertime * parms[3];
6459 index -= floor(index);
6460 switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6463 case Q3WAVEFUNC_NONE:
6464 case Q3WAVEFUNC_NOISE:
6465 case Q3WAVEFUNC_COUNT:
6468 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6469 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6470 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6471 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6472 case Q3WAVEFUNC_TRIANGLE:
6474 f = index - floor(index);
6487 f = parms[0] + parms[1] * f;
6488 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6489 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6493 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6500 matrix4x4_t matrix, temp;
6501 // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6502 // it's better to have one huge fixup every 9 hours than gradual
6503 // degradation over time which looks consistently bad after many hours.
6505 // tcmod scroll in particular suffers from this degradation which can't be
6506 // effectively worked around even with floor() tricks because we don't
6507 // know if tcmod scroll is the last tcmod being applied, and for clampmap
6508 // a workaround involving floor() would be incorrect anyway...
6509 shadertime = rsurface.shadertime;
6510 if (shadertime >= 32768.0f)
6511 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6512 switch(tcmod->tcmod)
6516 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6517 matrix = r_waterscrollmatrix;
6519 matrix = identitymatrix;
6521 case Q3TCMOD_ENTITYTRANSLATE:
6522 // this is used in Q3 to allow the gamecode to control texcoord
6523 // scrolling on the entity, which is not supported in darkplaces yet.
6524 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6526 case Q3TCMOD_ROTATE:
6527 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6528 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6529 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6532 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6534 case Q3TCMOD_SCROLL:
6535 // this particular tcmod is a "bug for bug" compatible one with regards to
6536 // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6537 // specifically did the wrapping and so we must mimic that...
6538 offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6539 offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6540 Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6542 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6543 w = (int) tcmod->parms[0];
6544 h = (int) tcmod->parms[1];
6545 f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6547 idx = (int) floor(f * w * h);
6548 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6550 case Q3TCMOD_STRETCH:
6551 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6552 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6554 case Q3TCMOD_TRANSFORM:
6555 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
6556 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
6557 VectorSet(tcmat + 6, 0 , 0 , 1);
6558 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
6559 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6561 case Q3TCMOD_TURBULENT:
6562 // this is handled in the RSurf_PrepareVertices function
6563 matrix = identitymatrix;
6567 Matrix4x4_Concat(texmatrix, &matrix, &temp);
6570 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6572 int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6573 char name[MAX_QPATH];
6574 skinframe_t *skinframe;
6575 unsigned char pixels[296*194];
6576 strlcpy(cache->name, skinname, sizeof(cache->name));
6577 dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6578 if (developer_loading.integer)
6579 Con_Printf("loading %s\n", name);
6580 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6581 if (!skinframe || !skinframe->base)
6584 fs_offset_t filesize;
6586 f = FS_LoadFile(name, tempmempool, true, &filesize);
6589 if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6590 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6594 cache->skinframe = skinframe;
6597 texture_t *R_GetCurrentTexture(texture_t *t)
6600 const entity_render_t *ent = rsurface.entity;
6601 dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6602 q3shaderinfo_layer_tcmod_t *tcmod;
6603 float specularscale = 0.0f;
6605 if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6606 return t->currentframe;
6607 t->update_lastrenderframe = r_textureframe;
6608 t->update_lastrenderentity = (void *)ent;
6610 if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6611 t->camera_entity = ent->entitynumber;
6613 t->camera_entity = 0;
6615 // switch to an alternate material if this is a q1bsp animated material
6617 texture_t *texture = t;
6618 int s = rsurface.ent_skinnum;
6619 if ((unsigned int)s >= (unsigned int)model->numskins)
6621 if (model->skinscenes)
6623 if (model->skinscenes[s].framecount > 1)
6624 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6626 s = model->skinscenes[s].firstframe;
6629 t = t + s * model->num_surfaces;
6632 // use an alternate animation if the entity's frame is not 0,
6633 // and only if the texture has an alternate animation
6634 if (t->animated == 2) // q2bsp
6635 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6636 else if (rsurface.ent_alttextures && t->anim_total[1])
6637 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6639 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6641 texture->currentframe = t;
6644 // update currentskinframe to be a qw skin or animation frame
6645 if (rsurface.ent_qwskin >= 0)
6647 i = rsurface.ent_qwskin;
6648 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6650 r_qwskincache_size = cl.maxclients;
6652 Mem_Free(r_qwskincache);
6653 r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6655 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6656 R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6657 t->currentskinframe = r_qwskincache[i].skinframe;
6658 if (t->materialshaderpass && t->currentskinframe == NULL)
6659 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6661 else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6662 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6663 if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6664 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6666 t->currentmaterialflags = t->basematerialflags;
6667 t->currentalpha = rsurface.entity->alpha * t->basealpha;
6668 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6669 t->currentalpha *= r_wateralpha.value;
6670 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6671 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6672 if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6673 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6675 // decide on which type of lighting to use for this surface
6676 if (rsurface.entity->render_modellight_forced)
6677 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6678 if (rsurface.entity->render_rtlight_disabled)
6679 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6680 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6682 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6683 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6684 for (q = 0; q < 3; q++)
6686 t->render_glowmod[q] = rsurface.entity->glowmod[q];
6687 t->render_modellight_lightdir[q] = q == 2;
6688 t->render_modellight_ambient[q] = 1;
6689 t->render_modellight_diffuse[q] = 0;
6690 t->render_modellight_specular[q] = 0;
6691 t->render_lightmap_ambient[q] = 0;
6692 t->render_lightmap_diffuse[q] = 0;
6693 t->render_lightmap_specular[q] = 0;
6694 t->render_rtlight_diffuse[q] = 0;
6695 t->render_rtlight_specular[q] = 0;
6698 else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6700 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6701 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6702 for (q = 0; q < 3; q++)
6704 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6705 t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6706 t->render_modellight_lightdir[q] = q == 2;
6707 t->render_modellight_diffuse[q] = 0;
6708 t->render_modellight_specular[q] = 0;
6709 t->render_lightmap_ambient[q] = 0;
6710 t->render_lightmap_diffuse[q] = 0;
6711 t->render_lightmap_specular[q] = 0;
6712 t->render_rtlight_diffuse[q] = 0;
6713 t->render_rtlight_specular[q] = 0;
6716 else if (FAKELIGHT_ENABLED)
6718 // no modellight if using fakelight for the map
6719 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6720 for (q = 0; q < 3; q++)
6722 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6723 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6724 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6725 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6726 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6727 t->render_lightmap_ambient[q] = 0;
6728 t->render_lightmap_diffuse[q] = 0;
6729 t->render_lightmap_specular[q] = 0;
6730 t->render_rtlight_diffuse[q] = 0;
6731 t->render_rtlight_specular[q] = 0;
6734 else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6736 // ambient + single direction light (modellight)
6737 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6738 for (q = 0; q < 3; q++)
6740 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6741 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6742 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6743 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6744 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6745 t->render_lightmap_ambient[q] = 0;
6746 t->render_lightmap_diffuse[q] = 0;
6747 t->render_lightmap_specular[q] = 0;
6748 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6749 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6754 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6755 for (q = 0; q < 3; q++)
6757 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6758 t->render_modellight_lightdir[q] = q == 2;
6759 t->render_modellight_ambient[q] = 0;
6760 t->render_modellight_diffuse[q] = 0;
6761 t->render_modellight_specular[q] = 0;
6762 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6763 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6764 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6765 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6766 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6770 if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6772 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6773 // attribute, we punt it to the lightmap path and hope for the best,
6774 // but lighting doesn't work.
6776 // FIXME: this is fine for effects but CSQC polygons should be subject
6778 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6779 for (q = 0; q < 3; q++)
6781 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6782 t->render_modellight_lightdir[q] = q == 2;
6783 t->render_modellight_ambient[q] = 0;
6784 t->render_modellight_diffuse[q] = 0;
6785 t->render_modellight_specular[q] = 0;
6786 t->render_lightmap_ambient[q] = 0;
6787 t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6788 t->render_lightmap_specular[q] = 0;
6789 t->render_rtlight_diffuse[q] = 0;
6790 t->render_rtlight_specular[q] = 0;
6794 for (q = 0; q < 3; q++)
6796 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6797 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6800 if (rsurface.ent_flags & RENDER_ADDITIVE)
6801 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6802 else if (t->currentalpha < 1)
6803 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6804 // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6805 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6806 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6807 if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6808 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6809 if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6810 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6811 if (t->backgroundshaderpass)
6812 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6813 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6815 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6816 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6819 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6820 if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6822 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6823 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6825 if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6826 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6828 // there is no tcmod
6829 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6831 t->currenttexmatrix = r_waterscrollmatrix;
6832 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6834 else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6836 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6837 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6840 if (t->materialshaderpass)
6841 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6842 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6844 t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6845 if (t->currentskinframe->qpixels)
6846 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6847 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6848 if (!t->basetexture)
6849 t->basetexture = r_texture_notexture;
6850 t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6851 t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6852 t->nmaptexture = t->currentskinframe->nmap;
6853 if (!t->nmaptexture)
6854 t->nmaptexture = r_texture_blanknormalmap;
6855 t->glosstexture = r_texture_black;
6856 t->glowtexture = t->currentskinframe->glow;
6857 t->fogtexture = t->currentskinframe->fog;
6858 t->reflectmasktexture = t->currentskinframe->reflect;
6859 if (t->backgroundshaderpass)
6861 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6862 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6863 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6864 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6865 t->backgroundglosstexture = r_texture_black;
6866 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6867 if (!t->backgroundnmaptexture)
6868 t->backgroundnmaptexture = r_texture_blanknormalmap;
6869 // make sure that if glow is going to be used, both textures are not NULL
6870 if (!t->backgroundglowtexture && t->glowtexture)
6871 t->backgroundglowtexture = r_texture_black;
6872 if (!t->glowtexture && t->backgroundglowtexture)
6873 t->glowtexture = r_texture_black;
6877 t->backgroundbasetexture = r_texture_white;
6878 t->backgroundnmaptexture = r_texture_blanknormalmap;
6879 t->backgroundglosstexture = r_texture_black;
6880 t->backgroundglowtexture = NULL;
6882 t->specularpower = r_shadow_glossexponent.value;
6883 // TODO: store reference values for these in the texture?
6884 if (r_shadow_gloss.integer > 0)
6886 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6888 if (r_shadow_glossintensity.value > 0)
6890 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6891 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6892 specularscale = r_shadow_glossintensity.value;
6895 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6897 t->glosstexture = r_texture_white;
6898 t->backgroundglosstexture = r_texture_white;
6899 specularscale = r_shadow_gloss2intensity.value;
6900 t->specularpower = r_shadow_gloss2exponent.value;
6903 specularscale *= t->specularscalemod;
6904 t->specularpower *= t->specularpowermod;
6906 // lightmaps mode looks bad with dlights using actual texturing, so turn
6907 // off the colormap and glossmap, but leave the normalmap on as it still
6908 // accurately represents the shading involved
6909 if (gl_lightmaps.integer)
6911 t->basetexture = r_texture_grey128;
6912 t->pantstexture = r_texture_black;
6913 t->shirttexture = r_texture_black;
6914 if (gl_lightmaps.integer < 2)
6915 t->nmaptexture = r_texture_blanknormalmap;
6916 t->glosstexture = r_texture_black;
6917 t->glowtexture = NULL;
6918 t->fogtexture = NULL;
6919 t->reflectmasktexture = NULL;
6920 t->backgroundbasetexture = NULL;
6921 if (gl_lightmaps.integer < 2)
6922 t->backgroundnmaptexture = r_texture_blanknormalmap;
6923 t->backgroundglosstexture = r_texture_black;
6924 t->backgroundglowtexture = NULL;
6926 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6929 if (specularscale != 1.0f)
6931 for (q = 0; q < 3; q++)
6933 t->render_modellight_specular[q] *= specularscale;
6934 t->render_lightmap_specular[q] *= specularscale;
6935 t->render_rtlight_specular[q] *= specularscale;
6939 t->currentnumlayers = 0;
6940 if (t->currentmaterialflags & MATERIALFLAG_WALL)
6942 int blendfunc1, blendfunc2;
6944 if (t->currentmaterialflags & MATERIALFLAG_ADD)
6946 blendfunc1 = GL_SRC_ALPHA;
6947 blendfunc2 = GL_ONE;
6949 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6951 blendfunc1 = GL_SRC_ALPHA;
6952 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
6954 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6956 blendfunc1 = t->customblendfunc[0];
6957 blendfunc2 = t->customblendfunc[1];
6961 blendfunc1 = GL_ONE;
6962 blendfunc2 = GL_ZERO;
6964 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
6965 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
6967 // basic lit geometry
6968 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
6969 // add pants/shirt if needed
6970 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
6971 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);
6972 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
6973 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);
6977 // basic lit geometry
6978 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);
6979 // add pants/shirt if needed
6980 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
6981 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);
6982 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
6983 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);
6984 // now add ambient passes if needed
6985 if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
6987 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);
6988 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
6989 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);
6990 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
6991 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);
6994 if (t->glowtexture != NULL && !gl_lightmaps.integer)
6995 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);
6996 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
6998 // if this is opaque use alpha blend which will darken the earlier
7001 // if this is an alpha blended material, all the earlier passes
7002 // were darkened by fog already, so we only need to add the fog
7003 // color ontop through the fog mask texture
7005 // if this is an additive blended material, all the earlier passes
7006 // were darkened by fog already, and we should not add fog color
7007 // (because the background was not darkened, there is no fog color
7008 // that was lost behind it).
7009 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);
7016 rsurfacestate_t rsurface;
7018 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7020 dp_model_t *model = ent->model;
7021 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7023 rsurface.entity = (entity_render_t *)ent;
7024 rsurface.skeleton = ent->skeleton;
7025 memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7026 rsurface.ent_skinnum = ent->skinnum;
7027 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;
7028 rsurface.ent_flags = ent->flags;
7029 if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7030 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7031 rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7032 rsurface.matrix = ent->matrix;
7033 rsurface.inversematrix = ent->inversematrix;
7034 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7035 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7036 R_EntityMatrix(&rsurface.matrix);
7037 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7038 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7039 rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7040 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7041 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7042 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7043 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7044 rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7045 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7046 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7047 if (ent->model->brush.submodel && !prepass)
7049 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7050 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7052 // if the animcache code decided it should use the shader path, skip the deform step
7053 rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7054 rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7055 rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7056 rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7057 rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7058 if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7060 if (ent->animcache_vertex3f)
7062 r_refdef.stats[r_stat_batch_entitycache_count]++;
7063 r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7064 r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7065 r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7066 rsurface.modelvertex3f = ent->animcache_vertex3f;
7067 rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7068 rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7069 rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7070 rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7071 rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7072 rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7073 rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7074 rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7075 rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7076 rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7077 rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7079 else if (wanttangents)
7081 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7082 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7083 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7084 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7085 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7086 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7087 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7088 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7089 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7090 rsurface.modelvertex3f_vertexbuffer = NULL;
7091 rsurface.modelvertex3f_bufferoffset = 0;
7092 rsurface.modelvertex3f_vertexbuffer = 0;
7093 rsurface.modelvertex3f_bufferoffset = 0;
7094 rsurface.modelsvector3f_vertexbuffer = 0;
7095 rsurface.modelsvector3f_bufferoffset = 0;
7096 rsurface.modeltvector3f_vertexbuffer = 0;
7097 rsurface.modeltvector3f_bufferoffset = 0;
7098 rsurface.modelnormal3f_vertexbuffer = 0;
7099 rsurface.modelnormal3f_bufferoffset = 0;
7101 else if (wantnormals)
7103 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7104 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7105 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7106 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7107 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7108 rsurface.modelsvector3f = NULL;
7109 rsurface.modeltvector3f = NULL;
7110 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7111 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7112 rsurface.modelvertex3f_vertexbuffer = NULL;
7113 rsurface.modelvertex3f_bufferoffset = 0;
7114 rsurface.modelvertex3f_vertexbuffer = 0;
7115 rsurface.modelvertex3f_bufferoffset = 0;
7116 rsurface.modelsvector3f_vertexbuffer = 0;
7117 rsurface.modelsvector3f_bufferoffset = 0;
7118 rsurface.modeltvector3f_vertexbuffer = 0;
7119 rsurface.modeltvector3f_bufferoffset = 0;
7120 rsurface.modelnormal3f_vertexbuffer = 0;
7121 rsurface.modelnormal3f_bufferoffset = 0;
7125 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7126 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7127 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7128 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7129 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7130 rsurface.modelsvector3f = NULL;
7131 rsurface.modeltvector3f = NULL;
7132 rsurface.modelnormal3f = NULL;
7133 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7134 rsurface.modelvertex3f_vertexbuffer = NULL;
7135 rsurface.modelvertex3f_bufferoffset = 0;
7136 rsurface.modelvertex3f_vertexbuffer = 0;
7137 rsurface.modelvertex3f_bufferoffset = 0;
7138 rsurface.modelsvector3f_vertexbuffer = 0;
7139 rsurface.modelsvector3f_bufferoffset = 0;
7140 rsurface.modeltvector3f_vertexbuffer = 0;
7141 rsurface.modeltvector3f_bufferoffset = 0;
7142 rsurface.modelnormal3f_vertexbuffer = 0;
7143 rsurface.modelnormal3f_bufferoffset = 0;
7145 rsurface.modelgeneratedvertex = true;
7149 if (rsurface.entityskeletaltransform3x4)
7151 r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7152 r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7153 r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7154 r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7158 r_refdef.stats[r_stat_batch_entitystatic_count]++;
7159 r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7160 r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7161 r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7163 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
7164 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7165 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7166 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7167 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7168 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7169 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7170 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7171 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7172 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
7173 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7174 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7175 rsurface.modelgeneratedvertex = false;
7177 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
7178 rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7179 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7180 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
7181 rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7182 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7183 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
7184 rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7185 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7186 rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7187 rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7188 rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7189 rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7190 rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7191 rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7192 rsurface.modelelement3i = model->surfmesh.data_element3i;
7193 rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7194 rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7195 rsurface.modelelement3s = model->surfmesh.data_element3s;
7196 rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7197 rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7198 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7199 rsurface.modelnumvertices = model->surfmesh.num_vertices;
7200 rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7201 rsurface.modelsurfaces = model->data_surfaces;
7202 rsurface.batchgeneratedvertex = false;
7203 rsurface.batchfirstvertex = 0;
7204 rsurface.batchnumvertices = 0;
7205 rsurface.batchfirsttriangle = 0;
7206 rsurface.batchnumtriangles = 0;
7207 rsurface.batchvertex3f = NULL;
7208 rsurface.batchvertex3f_vertexbuffer = NULL;
7209 rsurface.batchvertex3f_bufferoffset = 0;
7210 rsurface.batchsvector3f = NULL;
7211 rsurface.batchsvector3f_vertexbuffer = NULL;
7212 rsurface.batchsvector3f_bufferoffset = 0;
7213 rsurface.batchtvector3f = NULL;
7214 rsurface.batchtvector3f_vertexbuffer = NULL;
7215 rsurface.batchtvector3f_bufferoffset = 0;
7216 rsurface.batchnormal3f = NULL;
7217 rsurface.batchnormal3f_vertexbuffer = NULL;
7218 rsurface.batchnormal3f_bufferoffset = 0;
7219 rsurface.batchlightmapcolor4f = NULL;
7220 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7221 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7222 rsurface.batchtexcoordtexture2f = NULL;
7223 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7224 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7225 rsurface.batchtexcoordlightmap2f = NULL;
7226 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7227 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7228 rsurface.batchskeletalindex4ub = NULL;
7229 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7230 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7231 rsurface.batchskeletalweight4ub = NULL;
7232 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7233 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7234 rsurface.batchelement3i = NULL;
7235 rsurface.batchelement3i_indexbuffer = NULL;
7236 rsurface.batchelement3i_bufferoffset = 0;
7237 rsurface.batchelement3s = NULL;
7238 rsurface.batchelement3s_indexbuffer = NULL;
7239 rsurface.batchelement3s_bufferoffset = 0;
7240 rsurface.forcecurrenttextureupdate = false;
7243 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)
7245 rsurface.entity = r_refdef.scene.worldentity;
7246 rsurface.skeleton = NULL;
7247 rsurface.ent_skinnum = 0;
7248 rsurface.ent_qwskin = -1;
7249 rsurface.ent_flags = entflags;
7250 rsurface.shadertime = r_refdef.scene.time - shadertime;
7251 rsurface.modelnumvertices = numvertices;
7252 rsurface.modelnumtriangles = numtriangles;
7253 rsurface.matrix = *matrix;
7254 rsurface.inversematrix = *inversematrix;
7255 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7256 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7257 R_EntityMatrix(&rsurface.matrix);
7258 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7259 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7260 rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7261 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7262 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7263 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7264 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7265 rsurface.frameblend[0].lerp = 1;
7266 rsurface.ent_alttextures = false;
7267 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7268 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7269 rsurface.entityskeletaltransform3x4 = NULL;
7270 rsurface.entityskeletaltransform3x4buffer = NULL;
7271 rsurface.entityskeletaltransform3x4offset = 0;
7272 rsurface.entityskeletaltransform3x4size = 0;
7273 rsurface.entityskeletalnumtransforms = 0;
7274 r_refdef.stats[r_stat_batch_entitycustom_count]++;
7275 r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7276 r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7277 r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7280 rsurface.modelvertex3f = (float *)vertex3f;
7281 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7282 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7283 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7285 else if (wantnormals)
7287 rsurface.modelvertex3f = (float *)vertex3f;
7288 rsurface.modelsvector3f = NULL;
7289 rsurface.modeltvector3f = NULL;
7290 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7294 rsurface.modelvertex3f = (float *)vertex3f;
7295 rsurface.modelsvector3f = NULL;
7296 rsurface.modeltvector3f = NULL;
7297 rsurface.modelnormal3f = NULL;
7299 rsurface.modelvertex3f_vertexbuffer = 0;
7300 rsurface.modelvertex3f_bufferoffset = 0;
7301 rsurface.modelsvector3f_vertexbuffer = 0;
7302 rsurface.modelsvector3f_bufferoffset = 0;
7303 rsurface.modeltvector3f_vertexbuffer = 0;
7304 rsurface.modeltvector3f_bufferoffset = 0;
7305 rsurface.modelnormal3f_vertexbuffer = 0;
7306 rsurface.modelnormal3f_bufferoffset = 0;
7307 rsurface.modelgeneratedvertex = true;
7308 rsurface.modellightmapcolor4f = (float *)color4f;
7309 rsurface.modellightmapcolor4f_vertexbuffer = 0;
7310 rsurface.modellightmapcolor4f_bufferoffset = 0;
7311 rsurface.modeltexcoordtexture2f = (float *)texcoord2f;
7312 rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7313 rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7314 rsurface.modeltexcoordlightmap2f = NULL;
7315 rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7316 rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7317 rsurface.modelskeletalindex4ub = NULL;
7318 rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7319 rsurface.modelskeletalindex4ub_bufferoffset = 0;
7320 rsurface.modelskeletalweight4ub = NULL;
7321 rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7322 rsurface.modelskeletalweight4ub_bufferoffset = 0;
7323 rsurface.modelelement3i = (int *)element3i;
7324 rsurface.modelelement3i_indexbuffer = NULL;
7325 rsurface.modelelement3i_bufferoffset = 0;
7326 rsurface.modelelement3s = (unsigned short *)element3s;
7327 rsurface.modelelement3s_indexbuffer = NULL;
7328 rsurface.modelelement3s_bufferoffset = 0;
7329 rsurface.modellightmapoffsets = NULL;
7330 rsurface.modelsurfaces = NULL;
7331 rsurface.batchgeneratedvertex = false;
7332 rsurface.batchfirstvertex = 0;
7333 rsurface.batchnumvertices = 0;
7334 rsurface.batchfirsttriangle = 0;
7335 rsurface.batchnumtriangles = 0;
7336 rsurface.batchvertex3f = NULL;
7337 rsurface.batchvertex3f_vertexbuffer = NULL;
7338 rsurface.batchvertex3f_bufferoffset = 0;
7339 rsurface.batchsvector3f = NULL;
7340 rsurface.batchsvector3f_vertexbuffer = NULL;
7341 rsurface.batchsvector3f_bufferoffset = 0;
7342 rsurface.batchtvector3f = NULL;
7343 rsurface.batchtvector3f_vertexbuffer = NULL;
7344 rsurface.batchtvector3f_bufferoffset = 0;
7345 rsurface.batchnormal3f = NULL;
7346 rsurface.batchnormal3f_vertexbuffer = NULL;
7347 rsurface.batchnormal3f_bufferoffset = 0;
7348 rsurface.batchlightmapcolor4f = NULL;
7349 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7350 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7351 rsurface.batchtexcoordtexture2f = NULL;
7352 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7353 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7354 rsurface.batchtexcoordlightmap2f = NULL;
7355 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7356 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7357 rsurface.batchskeletalindex4ub = NULL;
7358 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7359 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7360 rsurface.batchskeletalweight4ub = NULL;
7361 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7362 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7363 rsurface.batchelement3i = NULL;
7364 rsurface.batchelement3i_indexbuffer = NULL;
7365 rsurface.batchelement3i_bufferoffset = 0;
7366 rsurface.batchelement3s = NULL;
7367 rsurface.batchelement3s_indexbuffer = NULL;
7368 rsurface.batchelement3s_bufferoffset = 0;
7369 rsurface.forcecurrenttextureupdate = true;
7371 if (rsurface.modelnumvertices && rsurface.modelelement3i)
7373 if ((wantnormals || wanttangents) && !normal3f)
7375 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7376 Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7378 if (wanttangents && !svector3f)
7380 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7381 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7382 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7387 float RSurf_FogPoint(const float *v)
7389 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7390 float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7391 float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7392 float FogHeightFade = r_refdef.fogheightfade;
7394 unsigned int fogmasktableindex;
7395 if (r_refdef.fogplaneviewabove)
7396 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7398 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7399 fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7400 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7403 float RSurf_FogVertex(const float *v)
7405 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7406 float FogPlaneViewDist = rsurface.fogplaneviewdist;
7407 float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7408 float FogHeightFade = rsurface.fogheightfade;
7410 unsigned int fogmasktableindex;
7411 if (r_refdef.fogplaneviewabove)
7412 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7414 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7415 fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7416 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7419 void RSurf_UploadBuffersForBatch(void)
7421 // upload buffer data for generated vertex data (dynamicvertex case) or index data (copytriangles case) and models that lack it to begin with (e.g. DrawQ_FlushUI)
7422 // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7423 if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7424 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7425 if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7426 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7427 if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7428 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7429 if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7430 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7431 if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7432 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7433 if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7434 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7435 if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7436 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7437 if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7438 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7439 if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7440 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7442 if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7443 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7444 else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7445 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7447 R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7448 R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7449 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7450 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7451 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7452 R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7453 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7454 R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7455 R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7456 R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7459 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7462 for (i = 0;i < numelements;i++)
7463 outelement3i[i] = inelement3i[i] + adjust;
7466 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7467 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7475 int surfacefirsttriangle;
7476 int surfacenumtriangles;
7477 int surfacefirstvertex;
7478 int surfaceendvertex;
7479 int surfacenumvertices;
7480 int batchnumsurfaces = texturenumsurfaces;
7481 int batchnumvertices;
7482 int batchnumtriangles;
7485 qboolean dynamicvertex;
7488 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7491 q3shaderinfo_deform_t *deform;
7492 const msurface_t *surface, *firstsurface;
7493 if (!texturenumsurfaces)
7495 // find vertex range of this surface batch
7497 firstsurface = texturesurfacelist[0];
7498 firsttriangle = firstsurface->num_firsttriangle;
7499 batchnumvertices = 0;
7500 batchnumtriangles = 0;
7501 firstvertex = endvertex = firstsurface->num_firstvertex;
7502 for (i = 0;i < texturenumsurfaces;i++)
7504 surface = texturesurfacelist[i];
7505 if (surface != firstsurface + i)
7507 surfacefirstvertex = surface->num_firstvertex;
7508 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7509 surfacenumvertices = surface->num_vertices;
7510 surfacenumtriangles = surface->num_triangles;
7511 if (firstvertex > surfacefirstvertex)
7512 firstvertex = surfacefirstvertex;
7513 if (endvertex < surfaceendvertex)
7514 endvertex = surfaceendvertex;
7515 batchnumvertices += surfacenumvertices;
7516 batchnumtriangles += surfacenumtriangles;
7519 r_refdef.stats[r_stat_batch_batches]++;
7521 r_refdef.stats[r_stat_batch_withgaps]++;
7522 r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7523 r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7524 r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7526 // we now know the vertex range used, and if there are any gaps in it
7527 rsurface.batchfirstvertex = firstvertex;
7528 rsurface.batchnumvertices = endvertex - firstvertex;
7529 rsurface.batchfirsttriangle = firsttriangle;
7530 rsurface.batchnumtriangles = batchnumtriangles;
7532 // check if any dynamic vertex processing must occur
7533 dynamicvertex = false;
7535 // we must use vertexbuffers for rendering, we can upload vertex buffers
7536 // easily enough but if the basevertex is non-zero it becomes more
7537 // difficult, so force dynamicvertex path in that case - it's suboptimal
7538 // but the most optimal case is to have the geometry sources provide their
7540 if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7541 dynamicvertex = true;
7543 // a cvar to force the dynamic vertex path to be taken, for debugging
7544 if (r_batch_debugdynamicvertexpath.integer)
7548 r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7549 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7550 r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7551 r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7553 dynamicvertex = true;
7556 // if there is a chance of animated vertex colors, it's a dynamic batch
7557 if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7561 r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7562 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7563 r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7564 r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7566 dynamicvertex = true;
7569 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7571 switch (deform->deform)
7574 case Q3DEFORM_PROJECTIONSHADOW:
7575 case Q3DEFORM_TEXT0:
7576 case Q3DEFORM_TEXT1:
7577 case Q3DEFORM_TEXT2:
7578 case Q3DEFORM_TEXT3:
7579 case Q3DEFORM_TEXT4:
7580 case Q3DEFORM_TEXT5:
7581 case Q3DEFORM_TEXT6:
7582 case Q3DEFORM_TEXT7:
7585 case Q3DEFORM_AUTOSPRITE:
7588 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7589 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7590 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7591 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7593 dynamicvertex = true;
7594 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7596 case Q3DEFORM_AUTOSPRITE2:
7599 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7600 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7601 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7602 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7604 dynamicvertex = true;
7605 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7607 case Q3DEFORM_NORMAL:
7610 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7611 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7612 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7613 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7615 dynamicvertex = true;
7616 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7619 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7620 break; // if wavefunc is a nop, ignore this transform
7623 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7624 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7625 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7626 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7628 dynamicvertex = true;
7629 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7631 case Q3DEFORM_BULGE:
7634 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7635 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7636 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7637 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7639 dynamicvertex = true;
7640 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7643 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7644 break; // if wavefunc is a nop, ignore this transform
7647 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7648 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7649 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7650 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7652 dynamicvertex = true;
7653 batchneed |= BATCHNEED_ARRAY_VERTEX;
7657 if (rsurface.texture->materialshaderpass)
7659 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7662 case Q3TCGEN_TEXTURE:
7664 case Q3TCGEN_LIGHTMAP:
7667 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7668 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7669 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7670 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7672 dynamicvertex = true;
7673 batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7675 case Q3TCGEN_VECTOR:
7678 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7679 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7680 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7681 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7683 dynamicvertex = true;
7684 batchneed |= BATCHNEED_ARRAY_VERTEX;
7686 case Q3TCGEN_ENVIRONMENT:
7689 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7690 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7691 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7692 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7694 dynamicvertex = true;
7695 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7698 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7702 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7703 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7704 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7705 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7707 dynamicvertex = true;
7708 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7712 // the caller can specify BATCHNEED_NOGAPS to force a batch with
7713 // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7714 // we ensure this by treating the vertex batch as dynamic...
7715 if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7719 r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7720 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7721 r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7722 r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7724 dynamicvertex = true;
7727 // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7728 if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7729 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7731 rsurface.batchvertex3f = rsurface.modelvertex3f;
7732 rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7733 rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7734 rsurface.batchsvector3f = rsurface.modelsvector3f;
7735 rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7736 rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7737 rsurface.batchtvector3f = rsurface.modeltvector3f;
7738 rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7739 rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7740 rsurface.batchnormal3f = rsurface.modelnormal3f;
7741 rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7742 rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7743 rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7744 rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer;
7745 rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
7746 rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7747 rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer;
7748 rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
7749 rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7750 rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7751 rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7752 rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7753 rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7754 rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7755 rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7756 rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7757 rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7758 rsurface.batchelement3i = rsurface.modelelement3i;
7759 rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7760 rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7761 rsurface.batchelement3s = rsurface.modelelement3s;
7762 rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7763 rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7764 rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7765 rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7766 rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7767 rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7768 rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7770 // if any dynamic vertex processing has to occur in software, we copy the
7771 // entire surface list together before processing to rebase the vertices
7772 // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7774 // if any gaps exist and we do not have a static vertex buffer, we have to
7775 // copy the surface list together to avoid wasting upload bandwidth on the
7776 // vertices in the gaps.
7778 // if gaps exist and we have a static vertex buffer, we can choose whether
7779 // to combine the index buffer ranges into one dynamic index buffer or
7780 // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7782 // in many cases the batch is reduced to one draw call.
7784 rsurface.batchmultidraw = false;
7785 rsurface.batchmultidrawnumsurfaces = 0;
7786 rsurface.batchmultidrawsurfacelist = NULL;
7790 // static vertex data, just set pointers...
7791 rsurface.batchgeneratedvertex = false;
7792 // if there are gaps, we want to build a combined index buffer,
7793 // otherwise use the original static buffer with an appropriate offset
7796 r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7797 r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7798 r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7799 r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7800 if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7802 rsurface.batchmultidraw = true;
7803 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7804 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7807 // build a new triangle elements array for this batch
7808 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7809 rsurface.batchfirsttriangle = 0;
7811 for (i = 0;i < texturenumsurfaces;i++)
7813 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7814 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7815 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7816 numtriangles += surfacenumtriangles;
7818 rsurface.batchelement3i_indexbuffer = NULL;
7819 rsurface.batchelement3i_bufferoffset = 0;
7820 rsurface.batchelement3s = NULL;
7821 rsurface.batchelement3s_indexbuffer = NULL;
7822 rsurface.batchelement3s_bufferoffset = 0;
7823 if (endvertex <= 65536)
7825 // make a 16bit (unsigned short) index array if possible
7826 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7827 for (i = 0;i < numtriangles*3;i++)
7828 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7833 r_refdef.stats[r_stat_batch_fast_batches] += 1;
7834 r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7835 r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7836 r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7841 // something needs software processing, do it for real...
7842 // we only directly handle separate array data in this case and then
7843 // generate interleaved data if needed...
7844 rsurface.batchgeneratedvertex = true;
7845 r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7846 r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7847 r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7848 r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7850 // now copy the vertex data into a combined array and make an index array
7851 // (this is what Quake3 does all the time)
7852 // we also apply any skeletal animation here that would have been done in
7853 // the vertex shader, because most of the dynamic vertex animation cases
7854 // need actual vertex positions and normals
7855 //if (dynamicvertex)
7857 rsurface.batchvertex3f = NULL;
7858 rsurface.batchvertex3f_vertexbuffer = NULL;
7859 rsurface.batchvertex3f_bufferoffset = 0;
7860 rsurface.batchsvector3f = NULL;
7861 rsurface.batchsvector3f_vertexbuffer = NULL;
7862 rsurface.batchsvector3f_bufferoffset = 0;
7863 rsurface.batchtvector3f = NULL;
7864 rsurface.batchtvector3f_vertexbuffer = NULL;
7865 rsurface.batchtvector3f_bufferoffset = 0;
7866 rsurface.batchnormal3f = NULL;
7867 rsurface.batchnormal3f_vertexbuffer = NULL;
7868 rsurface.batchnormal3f_bufferoffset = 0;
7869 rsurface.batchlightmapcolor4f = NULL;
7870 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7871 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7872 rsurface.batchtexcoordtexture2f = NULL;
7873 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7874 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7875 rsurface.batchtexcoordlightmap2f = NULL;
7876 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7877 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7878 rsurface.batchskeletalindex4ub = NULL;
7879 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7880 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7881 rsurface.batchskeletalweight4ub = NULL;
7882 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7883 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7884 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7885 rsurface.batchelement3i_indexbuffer = NULL;
7886 rsurface.batchelement3i_bufferoffset = 0;
7887 rsurface.batchelement3s = NULL;
7888 rsurface.batchelement3s_indexbuffer = NULL;
7889 rsurface.batchelement3s_bufferoffset = 0;
7890 rsurface.batchskeletaltransform3x4buffer = NULL;
7891 rsurface.batchskeletaltransform3x4offset = 0;
7892 rsurface.batchskeletaltransform3x4size = 0;
7893 // we'll only be setting up certain arrays as needed
7894 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7895 rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7896 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7897 rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7898 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7900 rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7901 rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7903 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7904 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7905 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7906 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7907 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7908 rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7909 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7911 rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7912 rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7916 for (i = 0;i < texturenumsurfaces;i++)
7918 surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7919 surfacenumvertices = texturesurfacelist[i]->num_vertices;
7920 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7921 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7922 // copy only the data requested
7923 if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7925 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7927 if (rsurface.batchvertex3f)
7928 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7930 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7932 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7934 if (rsurface.modelnormal3f)
7935 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7937 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7939 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7941 if (rsurface.modelsvector3f)
7943 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7944 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7948 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7949 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7952 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7954 if (rsurface.modellightmapcolor4f)
7955 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7957 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7959 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7961 if (rsurface.modeltexcoordtexture2f)
7962 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7964 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7966 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7968 if (rsurface.modeltexcoordlightmap2f)
7969 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7971 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7973 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7975 if (rsurface.modelskeletalindex4ub)
7977 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7978 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7982 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7983 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7984 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7985 for (j = 0;j < surfacenumvertices;j++)
7990 RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7991 numvertices += surfacenumvertices;
7992 numtriangles += surfacenumtriangles;
7995 // generate a 16bit index array as well if possible
7996 // (in general, dynamic batches fit)
7997 if (numvertices <= 65536)
7999 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8000 for (i = 0;i < numtriangles*3;i++)
8001 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8004 // since we've copied everything, the batch now starts at 0
8005 rsurface.batchfirstvertex = 0;
8006 rsurface.batchnumvertices = batchnumvertices;
8007 rsurface.batchfirsttriangle = 0;
8008 rsurface.batchnumtriangles = batchnumtriangles;
8011 // apply skeletal animation that would have been done in the vertex shader
8012 if (rsurface.batchskeletaltransform3x4)
8014 const unsigned char *si;
8015 const unsigned char *sw;
8017 const float *b = rsurface.batchskeletaltransform3x4;
8018 float *vp, *vs, *vt, *vn;
8020 float m[3][4], n[3][4];
8021 float tp[3], ts[3], tt[3], tn[3];
8022 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8023 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8024 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8025 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8026 si = rsurface.batchskeletalindex4ub;
8027 sw = rsurface.batchskeletalweight4ub;
8028 vp = rsurface.batchvertex3f;
8029 vs = rsurface.batchsvector3f;
8030 vt = rsurface.batchtvector3f;
8031 vn = rsurface.batchnormal3f;
8032 memset(m[0], 0, sizeof(m));
8033 memset(n[0], 0, sizeof(n));
8034 for (i = 0;i < batchnumvertices;i++)
8036 t[0] = b + si[0]*12;
8039 // common case - only one matrix
8053 else if (sw[2] + sw[3])
8056 t[1] = b + si[1]*12;
8057 t[2] = b + si[2]*12;
8058 t[3] = b + si[3]*12;
8059 w[0] = sw[0] * (1.0f / 255.0f);
8060 w[1] = sw[1] * (1.0f / 255.0f);
8061 w[2] = sw[2] * (1.0f / 255.0f);
8062 w[3] = sw[3] * (1.0f / 255.0f);
8063 // blend the matrices
8064 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8065 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8066 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8067 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8068 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8069 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8070 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8071 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8072 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8073 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8074 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8075 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8080 t[1] = b + si[1]*12;
8081 w[0] = sw[0] * (1.0f / 255.0f);
8082 w[1] = sw[1] * (1.0f / 255.0f);
8083 // blend the matrices
8084 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8085 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8086 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8087 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8088 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8089 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8090 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8091 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8092 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8093 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8094 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8095 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8099 // modify the vertex
8101 vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8102 vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8103 vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8107 // the normal transformation matrix is a set of cross products...
8108 CrossProduct(m[1], m[2], n[0]);
8109 CrossProduct(m[2], m[0], n[1]);
8110 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8112 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8113 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8114 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8115 VectorNormalize(vn);
8120 vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8121 vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8122 vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8123 VectorNormalize(vs);
8126 vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8127 vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8128 vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8129 VectorNormalize(vt);
8134 rsurface.batchskeletaltransform3x4 = NULL;
8135 rsurface.batchskeletalnumtransforms = 0;
8138 // q1bsp surfaces rendered in vertex color mode have to have colors
8139 // calculated based on lightstyles
8140 if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8142 // generate color arrays for the surfaces in this list
8147 const unsigned char *lm;
8148 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8149 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8150 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8152 for (i = 0;i < texturenumsurfaces;i++)
8154 surface = texturesurfacelist[i];
8155 offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8156 surfacenumvertices = surface->num_vertices;
8157 if (surface->lightmapinfo->samples)
8159 for (j = 0;j < surfacenumvertices;j++)
8161 lm = surface->lightmapinfo->samples + offsets[j];
8162 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8163 VectorScale(lm, scale, c);
8164 if (surface->lightmapinfo->styles[1] != 255)
8166 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8168 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8169 VectorMA(c, scale, lm, c);
8170 if (surface->lightmapinfo->styles[2] != 255)
8173 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8174 VectorMA(c, scale, lm, c);
8175 if (surface->lightmapinfo->styles[3] != 255)
8178 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8179 VectorMA(c, scale, lm, c);
8186 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);
8192 for (j = 0;j < surfacenumvertices;j++)
8194 Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8201 // if vertices are deformed (sprite flares and things in maps, possibly
8202 // water waves, bulges and other deformations), modify the copied vertices
8204 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8207 switch (deform->deform)
8210 case Q3DEFORM_PROJECTIONSHADOW:
8211 case Q3DEFORM_TEXT0:
8212 case Q3DEFORM_TEXT1:
8213 case Q3DEFORM_TEXT2:
8214 case Q3DEFORM_TEXT3:
8215 case Q3DEFORM_TEXT4:
8216 case Q3DEFORM_TEXT5:
8217 case Q3DEFORM_TEXT6:
8218 case Q3DEFORM_TEXT7:
8221 case Q3DEFORM_AUTOSPRITE:
8222 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8223 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8224 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8225 VectorNormalize(newforward);
8226 VectorNormalize(newright);
8227 VectorNormalize(newup);
8228 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8229 // rsurface.batchvertex3f_vertexbuffer = NULL;
8230 // rsurface.batchvertex3f_bufferoffset = 0;
8231 // rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8232 // rsurface.batchsvector3f_vertexbuffer = NULL;
8233 // rsurface.batchsvector3f_bufferoffset = 0;
8234 // rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8235 // rsurface.batchtvector3f_vertexbuffer = NULL;
8236 // rsurface.batchtvector3f_bufferoffset = 0;
8237 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8238 // rsurface.batchnormal3f_vertexbuffer = NULL;
8239 // rsurface.batchnormal3f_bufferoffset = 0;
8240 // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8241 if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8242 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8243 if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8244 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);
8245 // a single autosprite surface can contain multiple sprites...
8246 for (j = 0;j < batchnumvertices - 3;j += 4)
8248 VectorClear(center);
8249 for (i = 0;i < 4;i++)
8250 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8251 VectorScale(center, 0.25f, center);
8252 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8253 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8254 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8255 for (i = 0;i < 4;i++)
8257 VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8258 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8261 // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8262 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8263 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);
8265 case Q3DEFORM_AUTOSPRITE2:
8266 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8267 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8268 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8269 VectorNormalize(newforward);
8270 VectorNormalize(newright);
8271 VectorNormalize(newup);
8272 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8273 // rsurface.batchvertex3f_vertexbuffer = NULL;
8274 // rsurface.batchvertex3f_bufferoffset = 0;
8276 const float *v1, *v2;
8286 memset(shortest, 0, sizeof(shortest));
8287 // a single autosprite surface can contain multiple sprites...
8288 for (j = 0;j < batchnumvertices - 3;j += 4)
8290 VectorClear(center);
8291 for (i = 0;i < 4;i++)
8292 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8293 VectorScale(center, 0.25f, center);
8294 // find the two shortest edges, then use them to define the
8295 // axis vectors for rotating around the central axis
8296 for (i = 0;i < 6;i++)
8298 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8299 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8300 l = VectorDistance2(v1, v2);
8301 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8303 l += (1.0f / 1024.0f);
8304 if (shortest[0].length2 > l || i == 0)
8306 shortest[1] = shortest[0];
8307 shortest[0].length2 = l;
8308 shortest[0].v1 = v1;
8309 shortest[0].v2 = v2;
8311 else if (shortest[1].length2 > l || i == 1)
8313 shortest[1].length2 = l;
8314 shortest[1].v1 = v1;
8315 shortest[1].v2 = v2;
8318 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8319 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8320 // this calculates the right vector from the shortest edge
8321 // and the up vector from the edge midpoints
8322 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8323 VectorNormalize(right);
8324 VectorSubtract(end, start, up);
8325 VectorNormalize(up);
8326 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8327 VectorSubtract(rsurface.localvieworigin, center, forward);
8328 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8329 VectorNegate(forward, forward);
8330 VectorReflect(forward, 0, up, forward);
8331 VectorNormalize(forward);
8332 CrossProduct(up, forward, newright);
8333 VectorNormalize(newright);
8334 // rotate the quad around the up axis vector, this is made
8335 // especially easy by the fact we know the quad is flat,
8336 // so we only have to subtract the center position and
8337 // measure distance along the right vector, and then
8338 // multiply that by the newright vector and add back the
8340 // we also need to subtract the old position to undo the
8341 // displacement from the center, which we do with a
8342 // DotProduct, the subtraction/addition of center is also
8343 // optimized into DotProducts here
8344 l = DotProduct(right, center);
8345 for (i = 0;i < 4;i++)
8347 v1 = rsurface.batchvertex3f + 3*(j+i);
8348 f = DotProduct(right, v1) - l;
8349 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8353 if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8355 // rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8356 // rsurface.batchnormal3f_vertexbuffer = NULL;
8357 // rsurface.batchnormal3f_bufferoffset = 0;
8358 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8360 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8362 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8363 // rsurface.batchsvector3f_vertexbuffer = NULL;
8364 // rsurface.batchsvector3f_bufferoffset = 0;
8365 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8366 // rsurface.batchtvector3f_vertexbuffer = NULL;
8367 // rsurface.batchtvector3f_bufferoffset = 0;
8368 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);
8371 case Q3DEFORM_NORMAL:
8372 // deform the normals to make reflections wavey
8373 rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8374 rsurface.batchnormal3f_vertexbuffer = NULL;
8375 rsurface.batchnormal3f_bufferoffset = 0;
8376 for (j = 0;j < batchnumvertices;j++)
8379 float *normal = rsurface.batchnormal3f + 3*j;
8380 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8381 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8382 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8383 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8384 VectorNormalize(normal);
8386 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8388 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8389 // rsurface.batchsvector3f_vertexbuffer = NULL;
8390 // rsurface.batchsvector3f_bufferoffset = 0;
8391 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8392 // rsurface.batchtvector3f_vertexbuffer = NULL;
8393 // rsurface.batchtvector3f_bufferoffset = 0;
8394 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);
8398 // deform vertex array to make wavey water and flags and such
8399 waveparms[0] = deform->waveparms[0];
8400 waveparms[1] = deform->waveparms[1];
8401 waveparms[2] = deform->waveparms[2];
8402 waveparms[3] = deform->waveparms[3];
8403 if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8404 break; // if wavefunc is a nop, don't make a dynamic vertex array
8405 // this is how a divisor of vertex influence on deformation
8406 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8407 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8408 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8409 // rsurface.batchvertex3f_vertexbuffer = NULL;
8410 // rsurface.batchvertex3f_bufferoffset = 0;
8411 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8412 // rsurface.batchnormal3f_vertexbuffer = NULL;
8413 // rsurface.batchnormal3f_bufferoffset = 0;
8414 for (j = 0;j < batchnumvertices;j++)
8416 // if the wavefunc depends on time, evaluate it per-vertex
8419 waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8420 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8422 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8424 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8425 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8426 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8428 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8429 // rsurface.batchsvector3f_vertexbuffer = NULL;
8430 // rsurface.batchsvector3f_bufferoffset = 0;
8431 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8432 // rsurface.batchtvector3f_vertexbuffer = NULL;
8433 // rsurface.batchtvector3f_bufferoffset = 0;
8434 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);
8437 case Q3DEFORM_BULGE:
8438 // deform vertex array to make the surface have moving bulges
8439 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8440 // rsurface.batchvertex3f_vertexbuffer = NULL;
8441 // rsurface.batchvertex3f_bufferoffset = 0;
8442 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8443 // rsurface.batchnormal3f_vertexbuffer = NULL;
8444 // rsurface.batchnormal3f_bufferoffset = 0;
8445 for (j = 0;j < batchnumvertices;j++)
8447 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8448 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8450 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8451 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8452 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8454 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8455 // rsurface.batchsvector3f_vertexbuffer = NULL;
8456 // rsurface.batchsvector3f_bufferoffset = 0;
8457 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8458 // rsurface.batchtvector3f_vertexbuffer = NULL;
8459 // rsurface.batchtvector3f_bufferoffset = 0;
8460 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);
8464 // deform vertex array
8465 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8466 break; // if wavefunc is a nop, don't make a dynamic vertex array
8467 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8468 VectorScale(deform->parms, scale, waveparms);
8469 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8470 // rsurface.batchvertex3f_vertexbuffer = NULL;
8471 // rsurface.batchvertex3f_bufferoffset = 0;
8472 for (j = 0;j < batchnumvertices;j++)
8473 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8478 if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8480 // generate texcoords based on the chosen texcoord source
8481 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8484 case Q3TCGEN_TEXTURE:
8486 case Q3TCGEN_LIGHTMAP:
8487 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8488 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8489 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8490 if (rsurface.batchtexcoordlightmap2f)
8491 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8493 case Q3TCGEN_VECTOR:
8494 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8495 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8496 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8497 for (j = 0;j < batchnumvertices;j++)
8499 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8500 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8503 case Q3TCGEN_ENVIRONMENT:
8504 // make environment reflections using a spheremap
8505 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8506 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8507 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8508 for (j = 0;j < batchnumvertices;j++)
8510 // identical to Q3A's method, but executed in worldspace so
8511 // carried models can be shiny too
8513 float viewer[3], d, reflected[3], worldreflected[3];
8515 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8516 // VectorNormalize(viewer);
8518 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8520 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8521 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8522 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8523 // note: this is proportinal to viewer, so we can normalize later
8525 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8526 VectorNormalize(worldreflected);
8528 // note: this sphere map only uses world x and z!
8529 // so positive and negative y will LOOK THE SAME.
8530 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8531 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8535 // the only tcmod that needs software vertex processing is turbulent, so
8536 // check for it here and apply the changes if needed
8537 // and we only support that as the first one
8538 // (handling a mixture of turbulent and other tcmods would be problematic
8539 // without punting it entirely to a software path)
8540 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8542 amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8543 animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8544 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8545 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8546 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8547 for (j = 0;j < batchnumvertices;j++)
8549 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);
8550 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8556 void RSurf_DrawBatch(void)
8558 // sometimes a zero triangle surface (usually a degenerate patch) makes it
8559 // through the pipeline, killing it earlier in the pipeline would have
8560 // per-surface overhead rather than per-batch overhead, so it's best to
8561 // reject it here, before it hits glDraw.
8562 if (rsurface.batchnumtriangles == 0)
8565 // batch debugging code
8566 if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8572 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8573 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8576 for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8578 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8580 if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8581 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);
8588 if (rsurface.batchmultidraw)
8590 // issue multiple draws rather than copying index data
8591 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8592 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8593 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8594 for (i = 0;i < numsurfaces;)
8596 // combine consecutive surfaces as one draw
8597 for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8598 if (surfacelist[j] != surfacelist[k] + 1)
8600 firstvertex = surfacelist[i]->num_firstvertex;
8601 endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8602 firsttriangle = surfacelist[i]->num_firsttriangle;
8603 endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8604 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);
8610 // there is only one consecutive run of index data (may have been combined)
8611 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);
8615 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8617 // pick the closest matching water plane
8618 int planeindex, vertexindex, bestplaneindex = -1;
8622 r_waterstate_waterplane_t *p;
8623 qboolean prepared = false;
8625 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8627 if(p->camera_entity != rsurface.texture->camera_entity)
8632 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8634 if(rsurface.batchnumvertices == 0)
8637 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8639 Matrix4x4_Transform(&rsurface.matrix, v, vert);
8640 d += fabs(PlaneDiff(vert, &p->plane));
8642 if (bestd > d || bestplaneindex < 0)
8645 bestplaneindex = planeindex;
8648 return bestplaneindex;
8649 // NOTE: this MAY return a totally unrelated water plane; we can ignore
8650 // this situation though, as it might be better to render single larger
8651 // batches with useless stuff (backface culled for example) than to
8652 // render multiple smaller batches
8655 void RSurf_SetupDepthAndCulling(void)
8657 // submodels are biased to avoid z-fighting with world surfaces that they
8658 // may be exactly overlapping (avoids z-fighting artifacts on certain
8659 // doors and things in Quake maps)
8660 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8661 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8662 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8663 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8666 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8669 // transparent sky would be ridiculous
8670 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8672 R_SetupShader_Generic_NoTexture(false, false);
8673 skyrenderlater = true;
8674 RSurf_SetupDepthAndCulling();
8677 // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8678 if (r_sky_scissor.integer)
8680 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8681 for (i = 0; i < texturenumsurfaces; i++)
8683 const msurface_t *surf = texturesurfacelist[i];
8686 float mins[3], maxs[3];
8688 for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8690 Matrix4x4_Transform(&rsurface.matrix, v, p);
8693 if (mins[0] > p[0]) mins[0] = p[0];
8694 if (mins[1] > p[1]) mins[1] = p[1];
8695 if (mins[2] > p[2]) mins[2] = p[2];
8696 if (maxs[0] < p[0]) maxs[0] = p[0];
8697 if (maxs[1] < p[1]) maxs[1] = p[1];
8698 if (maxs[2] < p[2]) maxs[2] = p[2];
8702 VectorCopy(p, mins);
8703 VectorCopy(p, maxs);
8706 if (!R_ScissorForBBox(mins, maxs, scissor))
8710 if (skyscissor[0] > scissor[0])
8712 skyscissor[2] += skyscissor[0] - scissor[0];
8713 skyscissor[0] = scissor[0];
8715 if (skyscissor[1] > scissor[1])
8717 skyscissor[3] += skyscissor[1] - scissor[1];
8718 skyscissor[1] = scissor[1];
8720 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8721 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8722 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8723 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8726 Vector4Copy(scissor, skyscissor);
8731 // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8732 // skymasking on them, and Quake3 never did sky masking (unlike
8733 // software Quake and software Quake2), so disable the sky masking
8734 // in Quake3 maps as it causes problems with q3map2 sky tricks,
8735 // and skymasking also looks very bad when noclipping outside the
8736 // level, so don't use it then either.
8737 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)
8739 R_Mesh_ResetTextureState();
8740 if (skyrendermasked)
8742 R_SetupShader_DepthOrShadow(false, false, false);
8743 // depth-only (masking)
8744 GL_ColorMask(0, 0, 0, 0);
8745 // just to make sure that braindead drivers don't draw
8746 // anything despite that colormask...
8747 GL_BlendFunc(GL_ZERO, GL_ONE);
8748 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8749 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8753 R_SetupShader_Generic_NoTexture(false, false);
8755 GL_BlendFunc(GL_ONE, GL_ZERO);
8756 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8757 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8758 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8761 if (skyrendermasked)
8762 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8764 R_Mesh_ResetTextureState();
8765 GL_Color(1, 1, 1, 1);
8768 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8769 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8770 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
8772 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8776 // render screenspace normalmap to texture
8778 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8783 // bind lightmap texture
8785 // water/refraction/reflection/camera surfaces have to be handled specially
8786 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8788 int start, end, startplaneindex;
8789 for (start = 0;start < texturenumsurfaces;start = end)
8791 startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8792 if(startplaneindex < 0)
8794 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8795 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8799 for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8801 // now that we have a batch using the same planeindex, render it
8802 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8804 // render water or distortion background
8806 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8808 // blend surface on top
8809 GL_DepthMask(false);
8810 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8813 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8815 // render surface with reflection texture as input
8816 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8817 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8824 // render surface batch normally
8825 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8826 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
8830 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8834 int texturesurfaceindex;
8836 const msurface_t *surface;
8837 float surfacecolor4f[4];
8839 // R_Mesh_ResetTextureState();
8840 R_SetupShader_Generic_NoTexture(false, false);
8842 GL_BlendFunc(GL_ONE, GL_ZERO);
8843 GL_DepthMask(writedepth);
8845 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8847 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8849 surface = texturesurfacelist[texturesurfaceindex];
8850 k = (int)(((size_t)surface) / sizeof(msurface_t));
8851 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8852 for (j = 0;j < surface->num_vertices;j++)
8854 Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8858 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8862 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
8865 RSurf_SetupDepthAndCulling();
8866 if (r_showsurfaces.integer && r_refdef.view.showdebug)
8868 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8871 switch (vid.renderpath)
8873 case RENDERPATH_GL32:
8874 case RENDERPATH_GLES2:
8875 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
8881 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8884 int texturenumsurfaces, endsurface;
8886 const msurface_t *surface;
8887 const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8889 RSurf_ActiveModelEntity(ent, true, true, false);
8891 if (r_transparentdepthmasking.integer)
8893 qboolean setup = false;
8894 for (i = 0;i < numsurfaces;i = j)
8897 surface = rsurface.modelsurfaces + surfacelist[i];
8898 texture = surface->texture;
8899 rsurface.texture = R_GetCurrentTexture(texture);
8900 rsurface.lightmaptexture = NULL;
8901 rsurface.deluxemaptexture = NULL;
8902 rsurface.uselightmaptexture = false;
8903 // scan ahead until we find a different texture
8904 endsurface = min(i + 1024, numsurfaces);
8905 texturenumsurfaces = 0;
8906 texturesurfacelist[texturenumsurfaces++] = surface;
8907 for (;j < endsurface;j++)
8909 surface = rsurface.modelsurfaces + surfacelist[j];
8910 if (texture != surface->texture)
8912 texturesurfacelist[texturenumsurfaces++] = surface;
8914 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8916 // render the range of surfaces as depth
8920 GL_ColorMask(0,0,0,0);
8923 GL_BlendFunc(GL_ONE, GL_ZERO);
8925 // R_Mesh_ResetTextureState();
8927 RSurf_SetupDepthAndCulling();
8928 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8929 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8930 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8934 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8937 for (i = 0;i < numsurfaces;i = j)
8940 surface = rsurface.modelsurfaces + surfacelist[i];
8941 texture = surface->texture;
8942 rsurface.texture = R_GetCurrentTexture(texture);
8943 // scan ahead until we find a different texture
8944 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8945 texturenumsurfaces = 0;
8946 texturesurfacelist[texturenumsurfaces++] = surface;
8947 if(FAKELIGHT_ENABLED)
8949 rsurface.lightmaptexture = NULL;
8950 rsurface.deluxemaptexture = NULL;
8951 rsurface.uselightmaptexture = false;
8952 for (;j < endsurface;j++)
8954 surface = rsurface.modelsurfaces + surfacelist[j];
8955 if (texture != surface->texture)
8957 texturesurfacelist[texturenumsurfaces++] = surface;
8962 rsurface.lightmaptexture = surface->lightmaptexture;
8963 rsurface.deluxemaptexture = surface->deluxemaptexture;
8964 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8965 for (;j < endsurface;j++)
8967 surface = rsurface.modelsurfaces + surfacelist[j];
8968 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8970 texturesurfacelist[texturenumsurfaces++] = surface;
8973 // render the range of surfaces
8974 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
8976 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8979 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8981 // transparent surfaces get pushed off into the transparent queue
8982 int surfacelistindex;
8983 const msurface_t *surface;
8984 vec3_t tempcenter, center;
8985 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8987 surface = texturesurfacelist[surfacelistindex];
8988 if (r_transparent_sortsurfacesbynearest.integer)
8990 tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8991 tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8992 tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8996 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8997 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8998 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9000 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9001 if (rsurface.entity->transparent_offset) // transparent offset
9003 center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9004 center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9005 center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9007 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);
9011 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9013 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9015 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9017 RSurf_SetupDepthAndCulling();
9018 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9019 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9020 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9024 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9028 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9030 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9033 if (!rsurface.texture->currentnumlayers)
9035 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9036 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9038 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9040 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9041 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9042 else if (!rsurface.texture->currentnumlayers)
9044 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9046 // in the deferred case, transparent surfaces were queued during prepass
9047 if (!r_shadow_usingdeferredprepass)
9048 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9052 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9053 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9058 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9062 R_FrameData_SetMark();
9063 // break the surface list down into batches by texture and use of lightmapping
9064 for (i = 0;i < numsurfaces;i = j)
9067 // texture is the base texture pointer, rsurface.texture is the
9068 // current frame/skin the texture is directing us to use (for example
9069 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9070 // use skin 1 instead)
9071 texture = surfacelist[i]->texture;
9072 rsurface.texture = R_GetCurrentTexture(texture);
9073 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9075 // if this texture is not the kind we want, skip ahead to the next one
9076 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9080 if(FAKELIGHT_ENABLED || depthonly || prepass)
9082 rsurface.lightmaptexture = NULL;
9083 rsurface.deluxemaptexture = NULL;
9084 rsurface.uselightmaptexture = false;
9085 // simply scan ahead until we find a different texture or lightmap state
9086 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9091 rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9092 rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9093 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9094 // simply scan ahead until we find a different texture or lightmap state
9095 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9098 // render the range of surfaces
9099 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9101 R_FrameData_ReturnToMark();
9104 float locboxvertex3f[6*4*3] =
9106 1,0,1, 1,0,0, 1,1,0, 1,1,1,
9107 0,1,1, 0,1,0, 0,0,0, 0,0,1,
9108 1,1,1, 1,1,0, 0,1,0, 0,1,1,
9109 0,0,1, 0,0,0, 1,0,0, 1,0,1,
9110 0,0,1, 1,0,1, 1,1,1, 0,1,1,
9111 1,0,0, 0,0,0, 0,1,0, 1,1,0
9114 unsigned short locboxelements[6*2*3] =
9124 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9127 cl_locnode_t *loc = (cl_locnode_t *)ent;
9129 float vertex3f[6*4*3];
9131 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9132 GL_DepthMask(false);
9133 GL_DepthRange(0, 1);
9134 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9136 GL_CullFace(GL_NONE);
9137 R_EntityMatrix(&identitymatrix);
9139 // R_Mesh_ResetTextureState();
9142 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9143 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9144 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9145 surfacelist[0] < 0 ? 0.5f : 0.125f);
9147 if (VectorCompare(loc->mins, loc->maxs))
9149 VectorSet(size, 2, 2, 2);
9150 VectorMA(loc->mins, -0.5f, size, mins);
9154 VectorCopy(loc->mins, mins);
9155 VectorSubtract(loc->maxs, loc->mins, size);
9158 for (i = 0;i < 6*4*3;)
9159 for (j = 0;j < 3;j++, i++)
9160 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9162 R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9163 R_SetupShader_Generic_NoTexture(false, false);
9164 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9167 void R_DrawLocs(void)
9170 cl_locnode_t *loc, *nearestloc;
9172 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9173 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9175 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9176 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9180 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9182 if (decalsystem->decals)
9183 Mem_Free(decalsystem->decals);
9184 memset(decalsystem, 0, sizeof(*decalsystem));
9187 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)
9193 // expand or initialize the system
9194 if (decalsystem->maxdecals <= decalsystem->numdecals)
9196 decalsystem_t old = *decalsystem;
9197 qboolean useshortelements;
9198 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9199 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9200 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)));
9201 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9202 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9203 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9204 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9205 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9206 if (decalsystem->numdecals)
9207 memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9209 Mem_Free(old.decals);
9210 for (i = 0;i < decalsystem->maxdecals*3;i++)
9211 decalsystem->element3i[i] = i;
9212 if (useshortelements)
9213 for (i = 0;i < decalsystem->maxdecals*3;i++)
9214 decalsystem->element3s[i] = i;
9217 // grab a decal and search for another free slot for the next one
9218 decals = decalsystem->decals;
9219 decal = decalsystem->decals + (i = decalsystem->freedecal++);
9220 for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9222 decalsystem->freedecal = i;
9223 if (decalsystem->numdecals <= i)
9224 decalsystem->numdecals = i + 1;
9226 // initialize the decal
9228 decal->triangleindex = triangleindex;
9229 decal->surfaceindex = surfaceindex;
9230 decal->decalsequence = decalsequence;
9231 decal->color4f[0][0] = c0[0];
9232 decal->color4f[0][1] = c0[1];
9233 decal->color4f[0][2] = c0[2];
9234 decal->color4f[0][3] = 1;
9235 decal->color4f[1][0] = c1[0];
9236 decal->color4f[1][1] = c1[1];
9237 decal->color4f[1][2] = c1[2];
9238 decal->color4f[1][3] = 1;
9239 decal->color4f[2][0] = c2[0];
9240 decal->color4f[2][1] = c2[1];
9241 decal->color4f[2][2] = c2[2];
9242 decal->color4f[2][3] = 1;
9243 decal->vertex3f[0][0] = v0[0];
9244 decal->vertex3f[0][1] = v0[1];
9245 decal->vertex3f[0][2] = v0[2];
9246 decal->vertex3f[1][0] = v1[0];
9247 decal->vertex3f[1][1] = v1[1];
9248 decal->vertex3f[1][2] = v1[2];
9249 decal->vertex3f[2][0] = v2[0];
9250 decal->vertex3f[2][1] = v2[1];
9251 decal->vertex3f[2][2] = v2[2];
9252 decal->texcoord2f[0][0] = t0[0];
9253 decal->texcoord2f[0][1] = t0[1];
9254 decal->texcoord2f[1][0] = t1[0];
9255 decal->texcoord2f[1][1] = t1[1];
9256 decal->texcoord2f[2][0] = t2[0];
9257 decal->texcoord2f[2][1] = t2[1];
9258 TriangleNormal(v0, v1, v2, decal->plane);
9259 VectorNormalize(decal->plane);
9260 decal->plane[3] = DotProduct(v0, decal->plane);
9263 extern cvar_t cl_decals_bias;
9264 extern cvar_t cl_decals_models;
9265 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9266 // baseparms, parms, temps
9267 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)
9272 const float *vertex3f;
9273 const float *normal3f;
9275 float points[2][9][3];
9282 e = rsurface.modelelement3i + 3*triangleindex;
9284 vertex3f = rsurface.modelvertex3f;
9285 normal3f = rsurface.modelnormal3f;
9289 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9291 index = 3*e[cornerindex];
9292 VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9297 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9299 index = 3*e[cornerindex];
9300 VectorCopy(vertex3f + index, v[cornerindex]);
9305 //TriangleNormal(v[0], v[1], v[2], normal);
9306 //if (DotProduct(normal, localnormal) < 0.0f)
9308 // clip by each of the box planes formed from the projection matrix
9309 // if anything survives, we emit the decal
9310 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]);
9313 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]);
9316 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]);
9319 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]);
9322 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]);
9325 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]);
9328 // some part of the triangle survived, so we have to accept it...
9331 // dynamic always uses the original triangle
9333 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9335 index = 3*e[cornerindex];
9336 VectorCopy(vertex3f + index, v[cornerindex]);
9339 for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9341 // convert vertex positions to texcoords
9342 Matrix4x4_Transform(projection, v[cornerindex], temp);
9343 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9344 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9345 // calculate distance fade from the projection origin
9346 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9347 f = bound(0.0f, f, 1.0f);
9348 c[cornerindex][0] = r * f;
9349 c[cornerindex][1] = g * f;
9350 c[cornerindex][2] = b * f;
9351 c[cornerindex][3] = 1.0f;
9352 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9355 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);
9357 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9358 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);
9360 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)
9362 matrix4x4_t projection;
9363 decalsystem_t *decalsystem;
9366 const msurface_t *surface;
9367 const msurface_t *surfaces;
9368 const int *surfacelist;
9369 const texture_t *texture;
9372 int surfacelistindex;
9375 float localorigin[3];
9376 float localnormal[3];
9384 int bih_triangles_count;
9385 int bih_triangles[256];
9386 int bih_surfaces[256];
9388 decalsystem = &ent->decalsystem;
9390 if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9392 R_DecalSystem_Reset(&ent->decalsystem);
9396 if (!model->brush.data_leafs && !cl_decals_models.integer)
9398 if (decalsystem->model)
9399 R_DecalSystem_Reset(decalsystem);
9403 if (decalsystem->model != model)
9404 R_DecalSystem_Reset(decalsystem);
9405 decalsystem->model = model;
9407 RSurf_ActiveModelEntity(ent, true, false, false);
9409 Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9410 Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9411 VectorNormalize(localnormal);
9412 localsize = worldsize*rsurface.inversematrixscale;
9413 localmins[0] = localorigin[0] - localsize;
9414 localmins[1] = localorigin[1] - localsize;
9415 localmins[2] = localorigin[2] - localsize;
9416 localmaxs[0] = localorigin[0] + localsize;
9417 localmaxs[1] = localorigin[1] + localsize;
9418 localmaxs[2] = localorigin[2] + localsize;
9420 //VectorCopy(localnormal, planes[4]);
9421 //VectorVectors(planes[4], planes[2], planes[0]);
9422 AnglesFromVectors(angles, localnormal, NULL, false);
9423 AngleVectors(angles, planes[0], planes[2], planes[4]);
9424 VectorNegate(planes[0], planes[1]);
9425 VectorNegate(planes[2], planes[3]);
9426 VectorNegate(planes[4], planes[5]);
9427 planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9428 planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9429 planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9430 planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9431 planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9432 planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9437 matrix4x4_t forwardprojection;
9438 Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9439 Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9444 float projectionvector[4][3];
9445 VectorScale(planes[0], ilocalsize, projectionvector[0]);
9446 VectorScale(planes[2], ilocalsize, projectionvector[1]);
9447 VectorScale(planes[4], ilocalsize, projectionvector[2]);
9448 projectionvector[0][0] = planes[0][0] * ilocalsize;
9449 projectionvector[0][1] = planes[1][0] * ilocalsize;
9450 projectionvector[0][2] = planes[2][0] * ilocalsize;
9451 projectionvector[1][0] = planes[0][1] * ilocalsize;
9452 projectionvector[1][1] = planes[1][1] * ilocalsize;
9453 projectionvector[1][2] = planes[2][1] * ilocalsize;
9454 projectionvector[2][0] = planes[0][2] * ilocalsize;
9455 projectionvector[2][1] = planes[1][2] * ilocalsize;
9456 projectionvector[2][2] = planes[2][2] * ilocalsize;
9457 projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9458 projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9459 projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9460 Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9464 dynamic = model->surfmesh.isanimated;
9465 numsurfacelist = model->nummodelsurfaces;
9466 surfacelist = model->sortedmodelsurfaces;
9467 surfaces = model->data_surfaces;
9470 bih_triangles_count = -1;
9473 if(model->render_bih.numleafs)
9474 bih = &model->render_bih;
9475 else if(model->collision_bih.numleafs)
9476 bih = &model->collision_bih;
9479 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9480 if(bih_triangles_count == 0)
9482 if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9484 if(bih_triangles_count > 0)
9486 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9488 surfaceindex = bih_surfaces[triangleindex];
9489 surface = surfaces + surfaceindex;
9490 texture = surface->texture;
9491 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9493 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9495 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9500 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9502 surfaceindex = surfacelist[surfacelistindex];
9503 surface = surfaces + surfaceindex;
9504 // check cull box first because it rejects more than any other check
9505 if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9507 // skip transparent surfaces
9508 texture = surface->texture;
9509 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9511 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9513 numtriangles = surface->num_triangles;
9514 for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9515 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9520 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9521 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)
9523 int renderentityindex;
9526 entity_render_t *ent;
9528 if (!cl_decals_newsystem.integer)
9531 worldmins[0] = worldorigin[0] - worldsize;
9532 worldmins[1] = worldorigin[1] - worldsize;
9533 worldmins[2] = worldorigin[2] - worldsize;
9534 worldmaxs[0] = worldorigin[0] + worldsize;
9535 worldmaxs[1] = worldorigin[1] + worldsize;
9536 worldmaxs[2] = worldorigin[2] + worldsize;
9538 R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9540 for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9542 ent = r_refdef.scene.entities[renderentityindex];
9543 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9546 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9550 typedef struct r_decalsystem_splatqueue_s
9557 unsigned int decalsequence;
9559 r_decalsystem_splatqueue_t;
9561 int r_decalsystem_numqueued = 0;
9562 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9564 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)
9566 r_decalsystem_splatqueue_t *queue;
9568 if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9571 queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9572 VectorCopy(worldorigin, queue->worldorigin);
9573 VectorCopy(worldnormal, queue->worldnormal);
9574 Vector4Set(queue->color, r, g, b, a);
9575 Vector4Set(queue->tcrange, s1, t1, s2, t2);
9576 queue->worldsize = worldsize;
9577 queue->decalsequence = cl.decalsequence++;
9580 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9583 r_decalsystem_splatqueue_t *queue;
9585 for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9586 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);
9587 r_decalsystem_numqueued = 0;
9590 extern cvar_t cl_decals_max;
9591 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9594 decalsystem_t *decalsystem = &ent->decalsystem;
9596 unsigned int killsequence;
9601 if (!decalsystem->numdecals)
9604 if (r_showsurfaces.integer)
9607 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9609 R_DecalSystem_Reset(decalsystem);
9613 killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9614 lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9616 if (decalsystem->lastupdatetime)
9617 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9620 decalsystem->lastupdatetime = r_refdef.scene.time;
9621 numdecals = decalsystem->numdecals;
9623 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9625 if (decal->color4f[0][3])
9627 decal->lived += frametime;
9628 if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9630 memset(decal, 0, sizeof(*decal));
9631 if (decalsystem->freedecal > i)
9632 decalsystem->freedecal = i;
9636 decal = decalsystem->decals;
9637 while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9640 // collapse the array by shuffling the tail decals into the gaps
9643 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9644 decalsystem->freedecal++;
9645 if (decalsystem->freedecal == numdecals)
9647 decal[decalsystem->freedecal] = decal[--numdecals];
9650 decalsystem->numdecals = numdecals;
9654 // if there are no decals left, reset decalsystem
9655 R_DecalSystem_Reset(decalsystem);
9659 extern skinframe_t *decalskinframe;
9660 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9663 decalsystem_t *decalsystem = &ent->decalsystem;
9672 const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9675 numdecals = decalsystem->numdecals;
9679 if (r_showsurfaces.integer)
9682 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9684 R_DecalSystem_Reset(decalsystem);
9688 // if the model is static it doesn't matter what value we give for
9689 // wantnormals and wanttangents, so this logic uses only rules applicable
9690 // to a model, knowing that they are meaningless otherwise
9691 RSurf_ActiveModelEntity(ent, false, false, false);
9693 decalsystem->lastupdatetime = r_refdef.scene.time;
9695 faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9697 // update vertex positions for animated models
9698 v3f = decalsystem->vertex3f;
9699 c4f = decalsystem->color4f;
9700 t2f = decalsystem->texcoord2f;
9701 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9703 if (!decal->color4f[0][3])
9706 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9710 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9713 // update color values for fading decals
9714 if (decal->lived >= cl_decals_time.value)
9715 alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9719 c4f[ 0] = decal->color4f[0][0] * alpha;
9720 c4f[ 1] = decal->color4f[0][1] * alpha;
9721 c4f[ 2] = decal->color4f[0][2] * alpha;
9723 c4f[ 4] = decal->color4f[1][0] * alpha;
9724 c4f[ 5] = decal->color4f[1][1] * alpha;
9725 c4f[ 6] = decal->color4f[1][2] * alpha;
9727 c4f[ 8] = decal->color4f[2][0] * alpha;
9728 c4f[ 9] = decal->color4f[2][1] * alpha;
9729 c4f[10] = decal->color4f[2][2] * alpha;
9732 t2f[0] = decal->texcoord2f[0][0];
9733 t2f[1] = decal->texcoord2f[0][1];
9734 t2f[2] = decal->texcoord2f[1][0];
9735 t2f[3] = decal->texcoord2f[1][1];
9736 t2f[4] = decal->texcoord2f[2][0];
9737 t2f[5] = decal->texcoord2f[2][1];
9739 // update vertex positions for animated models
9740 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9742 e = rsurface.modelelement3i + 3*decal->triangleindex;
9743 VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9744 VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9745 VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9749 VectorCopy(decal->vertex3f[0], v3f);
9750 VectorCopy(decal->vertex3f[1], v3f + 3);
9751 VectorCopy(decal->vertex3f[2], v3f + 6);
9754 if (r_refdef.fogenabled)
9756 alpha = RSurf_FogVertex(v3f);
9757 VectorScale(c4f, alpha, c4f);
9758 alpha = RSurf_FogVertex(v3f + 3);
9759 VectorScale(c4f + 4, alpha, c4f + 4);
9760 alpha = RSurf_FogVertex(v3f + 6);
9761 VectorScale(c4f + 8, alpha, c4f + 8);
9772 r_refdef.stats[r_stat_drawndecals] += numtris;
9774 // now render the decals all at once
9775 // (this assumes they all use one particle font texture!)
9776 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);
9777 // R_Mesh_ResetTextureState();
9778 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9779 GL_DepthMask(false);
9780 GL_DepthRange(0, 1);
9781 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9783 GL_CullFace(GL_NONE);
9784 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9785 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9786 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9790 static void R_DrawModelDecals(void)
9794 // fade faster when there are too many decals
9795 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9796 for (i = 0;i < r_refdef.scene.numentities;i++)
9797 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9799 R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9800 for (i = 0;i < r_refdef.scene.numentities;i++)
9801 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9802 R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9804 R_DecalSystem_ApplySplatEntitiesQueue();
9806 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9807 for (i = 0;i < r_refdef.scene.numentities;i++)
9808 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9810 r_refdef.stats[r_stat_totaldecals] += numdecals;
9812 if (r_showsurfaces.integer)
9815 R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9817 for (i = 0;i < r_refdef.scene.numentities;i++)
9819 if (!r_refdef.viewcache.entityvisible[i])
9821 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9822 R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9826 extern cvar_t mod_collision_bih;
9827 static void R_DrawDebugModel(void)
9829 entity_render_t *ent = rsurface.entity;
9830 int i, j, flagsmask;
9831 const msurface_t *surface;
9832 dp_model_t *model = ent->model;
9834 if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9837 if (r_showoverdraw.value > 0)
9839 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9840 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9841 R_SetupShader_Generic_NoTexture(false, false);
9842 GL_DepthTest(false);
9843 GL_DepthMask(false);
9844 GL_DepthRange(0, 1);
9845 GL_BlendFunc(GL_ONE, GL_ONE);
9846 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9848 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9850 rsurface.texture = R_GetCurrentTexture(surface->texture);
9851 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9853 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9854 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9855 if (!rsurface.texture->currentlayers->depthmask)
9856 GL_Color(c, 0, 0, 1.0f);
9857 else if (ent == r_refdef.scene.worldentity)
9858 GL_Color(c, c, c, 1.0f);
9860 GL_Color(0, c, 0, 1.0f);
9861 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9865 rsurface.texture = NULL;
9868 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9870 // R_Mesh_ResetTextureState();
9871 R_SetupShader_Generic_NoTexture(false, false);
9872 GL_DepthRange(0, 1);
9873 GL_DepthTest(!r_showdisabledepthtest.integer);
9874 GL_DepthMask(false);
9875 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9877 if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9881 qboolean cullbox = false;
9882 const q3mbrush_t *brush;
9883 const bih_t *bih = &model->collision_bih;
9884 const bih_leaf_t *bihleaf;
9885 float vertex3f[3][3];
9886 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9887 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9889 if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9891 switch (bihleaf->type)
9894 brush = model->brush.data_brushes + bihleaf->itemindex;
9895 if (brush->colbrushf && brush->colbrushf->numtriangles)
9897 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);
9898 R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9899 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9902 case BIH_COLLISIONTRIANGLE:
9903 triangleindex = bihleaf->itemindex;
9904 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9905 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9906 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9907 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);
9908 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9909 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9911 case BIH_RENDERTRIANGLE:
9912 triangleindex = bihleaf->itemindex;
9913 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9914 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9915 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9916 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);
9917 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9918 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9924 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9927 if (r_showtris.value > 0 && qglPolygonMode)
9929 if (r_showdisabledepthtest.integer)
9931 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9932 GL_DepthMask(false);
9936 GL_BlendFunc(GL_ONE, GL_ZERO);
9939 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9940 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9942 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9944 rsurface.texture = R_GetCurrentTexture(surface->texture);
9945 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9947 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9948 if (!rsurface.texture->currentlayers->depthmask)
9949 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9950 else if (ent == r_refdef.scene.worldentity)
9951 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9953 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9954 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9958 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9959 rsurface.texture = NULL;
9963 // FIXME! implement r_shownormals with just triangles
9964 if (r_shownormals.value != 0 && qglBegin)
9968 if (r_showdisabledepthtest.integer)
9970 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9971 GL_DepthMask(false);
9975 GL_BlendFunc(GL_ONE, GL_ZERO);
9978 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9980 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9982 rsurface.texture = R_GetCurrentTexture(surface->texture);
9983 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9985 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9987 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9989 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9991 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9992 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9993 qglVertex3f(v[0], v[1], v[2]);
9994 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9995 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9996 qglVertex3f(v[0], v[1], v[2]);
9999 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10001 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10003 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10004 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10005 qglVertex3f(v[0], v[1], v[2]);
10006 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10007 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10008 qglVertex3f(v[0], v[1], v[2]);
10011 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10013 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10015 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10016 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10017 qglVertex3f(v[0], v[1], v[2]);
10018 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10019 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10020 qglVertex3f(v[0], v[1], v[2]);
10023 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10025 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10027 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10028 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10029 qglVertex3f(v[0], v[1], v[2]);
10030 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10031 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10032 qglVertex3f(v[0], v[1], v[2]);
10039 rsurface.texture = NULL;
10045 int r_maxsurfacelist = 0;
10046 const msurface_t **r_surfacelist = NULL;
10047 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10049 int i, j, endj, flagsmask;
10050 dp_model_t *model = ent->model;
10051 msurface_t *surfaces;
10052 unsigned char *update;
10053 int numsurfacelist = 0;
10057 if (r_maxsurfacelist < model->num_surfaces)
10059 r_maxsurfacelist = model->num_surfaces;
10061 Mem_Free((msurface_t **)r_surfacelist);
10062 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10065 if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10066 RSurf_ActiveModelEntity(ent, false, false, false);
10068 RSurf_ActiveModelEntity(ent, true, true, true);
10069 else if (depthonly)
10070 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10072 RSurf_ActiveModelEntity(ent, true, true, false);
10074 surfaces = model->data_surfaces;
10075 update = model->brushq1.lightmapupdateflags;
10077 // update light styles
10078 if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10080 model_brush_lightstyleinfo_t *style;
10081 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10083 if (style->value != r_refdef.scene.lightstylevalue[style->style])
10085 int *list = style->surfacelist;
10086 style->value = r_refdef.scene.lightstylevalue[style->style];
10087 for (j = 0;j < style->numsurfaces;j++)
10088 update[list[j]] = true;
10093 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10097 R_DrawDebugModel();
10098 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10102 rsurface.lightmaptexture = NULL;
10103 rsurface.deluxemaptexture = NULL;
10104 rsurface.uselightmaptexture = false;
10105 rsurface.texture = NULL;
10106 rsurface.rtlight = NULL;
10107 numsurfacelist = 0;
10108 // add visible surfaces to draw list
10109 if (ent == r_refdef.scene.worldentity)
10111 // for the world entity, check surfacevisible
10112 for (i = 0;i < model->nummodelsurfaces;i++)
10114 j = model->sortedmodelsurfaces[i];
10115 if (r_refdef.viewcache.world_surfacevisible[j])
10116 r_surfacelist[numsurfacelist++] = surfaces + j;
10121 // for ui we have to preserve the order of surfaces
10122 for (i = 0; i < model->nummodelsurfaces; i++)
10123 r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10127 // add all surfaces
10128 for (i = 0; i < model->nummodelsurfaces; i++)
10129 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10131 // don't do anything if there were no surfaces
10132 if (!numsurfacelist)
10134 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10137 // update lightmaps if needed
10141 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10146 R_BuildLightMap(ent, surfaces + j);
10151 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10153 // add to stats if desired
10154 if (r_speeds.integer && !skysurfaces && !depthonly)
10156 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10157 for (j = 0;j < numsurfacelist;j++)
10158 r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10161 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10164 void R_DebugLine(vec3_t start, vec3_t end)
10166 dp_model_t *mod = CL_Mesh_UI();
10168 int e0, e1, e2, e3;
10169 float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10170 float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10171 float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10174 // transform to screen coords first
10175 Vector4Set(w[0], start[0], start[1], start[2], 1);
10176 Vector4Set(w[1], end[0], end[1], end[2], 1);
10177 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10178 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10179 x1 = s[0][0] * vid_conwidth.value / vid.width;
10180 y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10181 x2 = s[1][0] * vid_conwidth.value / vid.width;
10182 y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10183 //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10185 // add the line to the UI mesh for drawing later
10187 // width is measured in real pixels
10188 if (fabs(x2 - x1) > fabs(y2 - y1))
10191 offsety = 0.5f * width * vid_conheight.value / vid.height;
10195 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10198 surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
10199 e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10200 e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10201 e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10202 e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10203 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10204 Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10209 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10212 static texture_t texture;
10213 static msurface_t surface;
10214 const msurface_t *surfacelist = &surface;
10216 // fake enough texture and surface state to render this geometry
10218 texture.update_lastrenderframe = -1; // regenerate this texture
10219 texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10220 texture.basealpha = 1.0f;
10221 texture.currentskinframe = skinframe;
10222 texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10223 texture.offsetmapping = OFFSETMAPPING_OFF;
10224 texture.offsetscale = 1;
10225 texture.specularscalemod = 1;
10226 texture.specularpowermod = 1;
10227 texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10228 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10229 // JUST GREP FOR "specularscalemod = 1".
10231 for (q = 0; q < 3; q++)
10233 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10234 texture.render_modellight_lightdir[q] = q == 2;
10235 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10236 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10237 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10238 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10239 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10240 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10241 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10242 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10244 texture.currentalpha = 1.0f;
10246 surface.texture = &texture;
10247 surface.num_triangles = numtriangles;
10248 surface.num_firsttriangle = firsttriangle;
10249 surface.num_vertices = numvertices;
10250 surface.num_firstvertex = firstvertex;
10253 rsurface.texture = R_GetCurrentTexture(surface.texture);
10254 rsurface.lightmaptexture = NULL;
10255 rsurface.deluxemaptexture = NULL;
10256 rsurface.uselightmaptexture = false;
10257 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10260 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)
10262 static msurface_t surface;
10263 const msurface_t *surfacelist = &surface;
10265 // fake enough texture and surface state to render this geometry
10266 surface.texture = texture;
10267 surface.num_triangles = numtriangles;
10268 surface.num_firsttriangle = firsttriangle;
10269 surface.num_vertices = numvertices;
10270 surface.num_firstvertex = firstvertex;
10273 rsurface.texture = R_GetCurrentTexture(surface.texture);
10274 rsurface.lightmaptexture = NULL;
10275 rsurface.deluxemaptexture = NULL;
10276 rsurface.uselightmaptexture = false;
10277 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);