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 %u\n", mode, permutation);
1371 R_GLSL_CompilePermutation(perm, mode, permutation);
1373 if (!r_glsl_permutation->program)
1375 // remove features until we find a valid permutation
1377 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1379 // reduce i more quickly whenever it would not remove any bits
1380 dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1381 if (!(permutation & j))
1384 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1385 if (!r_glsl_permutation->compiled)
1386 R_GLSL_CompilePermutation(perm, mode, permutation);
1387 if (r_glsl_permutation->program)
1390 if (i >= SHADERPERMUTATION_COUNT)
1392 //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1393 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1394 qglUseProgram(0);CHECKGLERROR
1395 return; // no bit left to clear, entire mode is broken
1400 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1402 if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1403 if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1404 if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1408 void R_GLSL_Restart_f(void)
1410 unsigned int i, limit;
1411 switch(vid.renderpath)
1413 case RENDERPATH_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 R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
1870 R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
1871 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
1872 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
1873 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
1874 R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
1875 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
1876 R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
1877 R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
1878 R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
1879 // this has to be after RSurf_PrepareVerticesForBatch
1880 if (rsurface.batchskeletaltransform3x4buffer)
1881 permutation |= SHADERPERMUTATION_SKELETAL;
1882 R_SetupShader_SetPermutationGLSL(mode, permutation);
1883 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1884 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);
1886 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1887 if (mode == SHADERMODE_LIGHTSOURCE)
1889 if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1890 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1891 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1892 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1893 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1894 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1896 // additive passes are only darkened by fog, not tinted
1897 if (r_glsl_permutation->loc_FogColor >= 0)
1898 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1899 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);
1903 if (mode == SHADERMODE_FLATCOLOR)
1905 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]);
1907 else if (mode == SHADERMODE_LIGHTDIRECTION)
1909 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]);
1910 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]);
1911 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]);
1912 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]);
1913 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]);
1914 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1915 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]);
1919 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]);
1920 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]);
1921 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]);
1922 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]);
1923 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]);
1925 // additive passes are only darkened by fog, not tinted
1926 if (r_glsl_permutation->loc_FogColor >= 0)
1928 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1929 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1931 qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1933 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);
1934 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]);
1935 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]);
1936 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);
1937 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);
1938 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1939 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1940 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);
1941 if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1943 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1944 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1945 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1946 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1948 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]);
1949 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]);
1953 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]);
1954 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]);
1957 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]);
1958 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));
1959 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1960 if (r_glsl_permutation->loc_Color_Pants >= 0)
1962 if (t->pantstexture)
1963 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1965 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1967 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1969 if (t->shirttexture)
1970 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1972 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1974 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]);
1975 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1976 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1977 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1978 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1979 r_glsl_offsetmapping_scale.value*t->offsetscale,
1980 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1981 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1982 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1984 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);
1985 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1986 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]);
1987 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1988 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);}
1989 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1991 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_texture_white );
1992 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_texture_white );
1993 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps , r_texture_gammaramps );
1994 if (r_glsl_permutation->tex_Texture_Normal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal , t->nmaptexture );
1995 if (r_glsl_permutation->tex_Texture_Color >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color , t->basetexture );
1996 if (r_glsl_permutation->tex_Texture_Gloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss , t->glosstexture );
1997 if (r_glsl_permutation->tex_Texture_Glow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow , t->glowtexture );
1998 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal , t->backgroundnmaptexture );
1999 if (r_glsl_permutation->tex_Texture_SecondaryColor >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor , t->backgroundbasetexture );
2000 if (r_glsl_permutation->tex_Texture_SecondaryGloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss , t->backgroundglosstexture );
2001 if (r_glsl_permutation->tex_Texture_SecondaryGlow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow , t->backgroundglowtexture );
2002 if (r_glsl_permutation->tex_Texture_Pants >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants , t->pantstexture );
2003 if (r_glsl_permutation->tex_Texture_Shirt >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt , t->shirttexture );
2004 if (r_glsl_permutation->tex_Texture_ReflectMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask , t->reflectmasktexture );
2005 if (r_glsl_permutation->tex_Texture_ReflectCube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2006 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture );
2007 if (r_glsl_permutation->tex_Texture_FogMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask , r_texture_fogattenuation );
2008 if (r_glsl_permutation->tex_Texture_Lightmap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2009 if (r_glsl_permutation->tex_Texture_Deluxemap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2010 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2011 if (rsurfacepass == RSURFPASS_BACKGROUND)
2013 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);
2014 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);
2015 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);
2019 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);
2021 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2022 if (r_glsl_permutation->tex_Texture_ScreenDiffuse >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse , r_shadow_prepasslightingdiffusetexture );
2023 if (r_glsl_permutation->tex_Texture_ScreenSpecular >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture );
2024 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2026 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture );
2027 if (rsurface.rtlight)
2029 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2030 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2033 if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2039 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2041 // select a permutation of the lighting shader appropriate to this
2042 // combination of texture, entity, light source, and fogging, only use the
2043 // minimum features necessary to avoid wasting rendering time in the
2044 // fragment shader on features that are not being used
2045 dpuint64 permutation = 0;
2046 unsigned int mode = 0;
2047 const float *lightcolorbase = rtlight->currentcolor;
2048 float ambientscale = rtlight->ambientscale;
2049 float diffusescale = rtlight->diffusescale;
2050 float specularscale = rtlight->specularscale;
2051 // this is the location of the light in view space
2052 vec3_t viewlightorigin;
2053 // this transforms from view space (camera) to light space (cubemap)
2054 matrix4x4_t viewtolight;
2055 matrix4x4_t lighttoview;
2056 float viewtolight16f[16];
2058 mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2059 if (rtlight->currentcubemap != r_texture_whitecube)
2060 permutation |= SHADERPERMUTATION_CUBEFILTER;
2061 if (diffusescale > 0)
2062 permutation |= SHADERPERMUTATION_DIFFUSE;
2063 if (specularscale > 0 && r_shadow_gloss.integer > 0)
2064 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2065 if (r_shadow_usingshadowmap2d)
2067 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2068 if (r_shadow_shadowmapvsdct)
2069 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2071 if (r_shadow_shadowmap2ddepthbuffer)
2072 permutation |= SHADERPERMUTATION_DEPTHRGB;
2074 if (vid.allowalphatocoverage)
2075 GL_AlphaToCoverage(false);
2076 Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2077 Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2078 Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2079 Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2080 switch(vid.renderpath)
2082 case RENDERPATH_GL32:
2083 case RENDERPATH_GLES2:
2084 R_SetupShader_SetPermutationGLSL(mode, permutation);
2085 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f( r_glsl_permutation->loc_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2086 if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight , 1, false, viewtolight16f);
2087 if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2088 if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2089 if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2090 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]);
2091 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]);
2092 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);
2093 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]);
2094 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/vid.width, 1.0f/vid.height);
2096 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2097 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2098 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2099 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2ddepthtexture );
2100 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2105 #define SKINFRAME_HASH 1024
2109 unsigned int loadsequence; // incremented each level change
2110 memexpandablearray_t array;
2111 skinframe_t *hash[SKINFRAME_HASH];
2114 r_skinframe_t r_skinframe;
2116 void R_SkinFrame_PrepareForPurge(void)
2118 r_skinframe.loadsequence++;
2119 // wrap it without hitting zero
2120 if (r_skinframe.loadsequence >= 200)
2121 r_skinframe.loadsequence = 1;
2124 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2128 // mark the skinframe as used for the purging code
2129 skinframe->loadsequence = r_skinframe.loadsequence;
2132 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2136 if (s->merged == s->base)
2138 R_PurgeTexture(s->stain); s->stain = NULL;
2139 R_PurgeTexture(s->merged); s->merged = NULL;
2140 R_PurgeTexture(s->base); s->base = NULL;
2141 R_PurgeTexture(s->pants); s->pants = NULL;
2142 R_PurgeTexture(s->shirt); s->shirt = NULL;
2143 R_PurgeTexture(s->nmap); s->nmap = NULL;
2144 R_PurgeTexture(s->gloss); s->gloss = NULL;
2145 R_PurgeTexture(s->glow); s->glow = NULL;
2146 R_PurgeTexture(s->fog); s->fog = NULL;
2147 R_PurgeTexture(s->reflect); s->reflect = NULL;
2148 s->loadsequence = 0;
2151 void R_SkinFrame_Purge(void)
2155 for (i = 0;i < SKINFRAME_HASH;i++)
2157 for (s = r_skinframe.hash[i];s;s = s->next)
2159 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2160 R_SkinFrame_PurgeSkinFrame(s);
2165 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2167 char basename[MAX_QPATH];
2169 Image_StripImageExtension(name, basename, sizeof(basename));
2171 if( last == NULL ) {
2173 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2174 item = r_skinframe.hash[hashindex];
2179 // linearly search through the hash bucket
2180 for( ; item ; item = item->next ) {
2181 if( !strcmp( item->basename, basename ) ) {
2188 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2191 int compareflags = textureflags & TEXF_IMPORTANTBITS;
2193 char basename[MAX_QPATH];
2195 Image_StripImageExtension(name, basename, sizeof(basename));
2197 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2198 for (item = r_skinframe.hash[hashindex];item;item = item->next)
2199 if (!strcmp(item->basename, basename) &&
2200 item->textureflags == compareflags &&
2201 item->comparewidth == comparewidth &&
2202 item->compareheight == compareheight &&
2203 item->comparecrc == comparecrc)
2210 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2211 memset(item, 0, sizeof(*item));
2212 strlcpy(item->basename, basename, sizeof(item->basename));
2213 item->textureflags = compareflags;
2214 item->comparewidth = comparewidth;
2215 item->compareheight = compareheight;
2216 item->comparecrc = comparecrc;
2217 item->next = r_skinframe.hash[hashindex];
2218 r_skinframe.hash[hashindex] = item;
2220 else if (textureflags & TEXF_FORCE_RELOAD)
2221 R_SkinFrame_PurgeSkinFrame(item);
2223 R_SkinFrame_MarkUsed(item);
2227 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2229 unsigned long long avgcolor[5], wsum; \
2237 for(pix = 0; pix < cnt; ++pix) \
2240 for(comp = 0; comp < 3; ++comp) \
2242 if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2245 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2247 for(comp = 0; comp < 3; ++comp) \
2248 avgcolor[comp] += getpixel * w; \
2251 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2252 avgcolor[4] += getpixel; \
2254 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2256 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2257 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2258 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2259 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2262 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2264 skinframe_t *skinframe;
2266 if (cls.state == ca_dedicated)
2269 // return an existing skinframe if already loaded
2270 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2271 if (skinframe && skinframe->base)
2274 // if the skinframe doesn't exist this will create it
2275 return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2278 extern cvar_t gl_picmip;
2279 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2282 unsigned char *pixels;
2283 unsigned char *bumppixels;
2284 unsigned char *basepixels = NULL;
2285 int basepixels_width = 0;
2286 int basepixels_height = 0;
2287 rtexture_t *ddsbase = NULL;
2288 qboolean ddshasalpha = false;
2289 float ddsavgcolor[4];
2290 char basename[MAX_QPATH];
2291 int miplevel = R_PicmipForFlags(textureflags);
2292 int savemiplevel = miplevel;
2296 if (cls.state == ca_dedicated)
2299 Image_StripImageExtension(name, basename, sizeof(basename));
2301 // check for DDS texture file first
2302 if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2304 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2305 if (basepixels == NULL && fallbacknotexture)
2306 basepixels = Image_GenerateNoTexture();
2307 if (basepixels == NULL)
2311 // FIXME handle miplevel
2313 if (developer_loading.integer)
2314 Con_Printf("loading skin \"%s\"\n", name);
2316 // we've got some pixels to store, so really allocate this new texture now
2318 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2319 textureflags &= ~TEXF_FORCE_RELOAD;
2320 skinframe->stain = NULL;
2321 skinframe->merged = NULL;
2322 skinframe->base = NULL;
2323 skinframe->pants = NULL;
2324 skinframe->shirt = NULL;
2325 skinframe->nmap = NULL;
2326 skinframe->gloss = NULL;
2327 skinframe->glow = NULL;
2328 skinframe->fog = NULL;
2329 skinframe->reflect = NULL;
2330 skinframe->hasalpha = false;
2331 // we could store the q2animname here too
2335 skinframe->base = ddsbase;
2336 skinframe->hasalpha = ddshasalpha;
2337 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2338 if (r_loadfog && skinframe->hasalpha)
2339 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);
2340 //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]);
2344 basepixels_width = image_width;
2345 basepixels_height = image_height;
2346 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);
2347 if (textureflags & TEXF_ALPHA)
2349 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2351 if (basepixels[j] < 255)
2353 skinframe->hasalpha = true;
2357 if (r_loadfog && skinframe->hasalpha)
2359 // has transparent pixels
2360 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2361 for (j = 0;j < image_width * image_height * 4;j += 4)
2366 pixels[j+3] = basepixels[j+3];
2368 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);
2372 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2374 //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]);
2375 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2376 R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2377 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2378 R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2384 mymiplevel = savemiplevel;
2385 if (r_loadnormalmap)
2386 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);
2387 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2389 skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2390 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2391 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2392 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2395 // _norm is the name used by tenebrae and has been adopted as standard
2396 if (r_loadnormalmap && skinframe->nmap == NULL)
2398 mymiplevel = savemiplevel;
2399 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2401 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);
2405 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2407 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2408 Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2409 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);
2411 Mem_Free(bumppixels);
2413 else if (r_shadow_bumpscale_basetexture.value > 0)
2415 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2416 Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2417 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);
2421 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2422 R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2426 // _luma is supported only for tenebrae compatibility
2427 // _glow is the preferred name
2428 mymiplevel = savemiplevel;
2429 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))))
2431 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);
2433 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2434 R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2436 Mem_Free(pixels);pixels = NULL;
2439 mymiplevel = savemiplevel;
2440 if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2442 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);
2444 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2445 R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2451 mymiplevel = savemiplevel;
2452 if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2454 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);
2456 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2457 R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2463 mymiplevel = savemiplevel;
2464 if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2466 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);
2468 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2469 R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2475 mymiplevel = savemiplevel;
2476 if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2478 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);
2480 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2481 R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2488 Mem_Free(basepixels);
2493 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)
2496 skinframe_t *skinframe;
2499 if (cls.state == ca_dedicated)
2502 // if already loaded just return it, otherwise make a new skinframe
2503 skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2504 if (skinframe->base)
2506 textureflags &= ~TEXF_FORCE_RELOAD;
2508 skinframe->stain = NULL;
2509 skinframe->merged = NULL;
2510 skinframe->base = NULL;
2511 skinframe->pants = NULL;
2512 skinframe->shirt = NULL;
2513 skinframe->nmap = NULL;
2514 skinframe->gloss = NULL;
2515 skinframe->glow = NULL;
2516 skinframe->fog = NULL;
2517 skinframe->reflect = NULL;
2518 skinframe->hasalpha = false;
2520 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2524 if (developer_loading.integer)
2525 Con_Printf("loading 32bit skin \"%s\"\n", name);
2527 if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2529 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2530 unsigned char *b = a + width * height * 4;
2531 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2532 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);
2535 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2536 if (textureflags & TEXF_ALPHA)
2538 for (i = 3;i < width * height * 4;i += 4)
2540 if (skindata[i] < 255)
2542 skinframe->hasalpha = true;
2546 if (r_loadfog && skinframe->hasalpha)
2548 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2549 memcpy(fogpixels, skindata, width * height * 4);
2550 for (i = 0;i < width * height * 4;i += 4)
2551 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2552 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2553 Mem_Free(fogpixels);
2557 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2558 //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]);
2563 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2567 skinframe_t *skinframe;
2569 if (cls.state == ca_dedicated)
2572 // if already loaded just return it, otherwise make a new skinframe
2573 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2574 if (skinframe->base)
2576 //textureflags &= ~TEXF_FORCE_RELOAD;
2578 skinframe->stain = NULL;
2579 skinframe->merged = NULL;
2580 skinframe->base = NULL;
2581 skinframe->pants = NULL;
2582 skinframe->shirt = NULL;
2583 skinframe->nmap = NULL;
2584 skinframe->gloss = NULL;
2585 skinframe->glow = NULL;
2586 skinframe->fog = NULL;
2587 skinframe->reflect = NULL;
2588 skinframe->hasalpha = false;
2590 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2594 if (developer_loading.integer)
2595 Con_Printf("loading quake skin \"%s\"\n", name);
2597 // 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)
2598 skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2599 memcpy(skinframe->qpixels, skindata, width*height);
2600 skinframe->qwidth = width;
2601 skinframe->qheight = height;
2604 for (i = 0;i < width * height;i++)
2605 featuresmask |= palette_featureflags[skindata[i]];
2607 skinframe->hasalpha = false;
2610 skinframe->hasalpha = true;
2611 skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2612 skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2613 skinframe->qgeneratemerged = true;
2614 skinframe->qgeneratebase = skinframe->qhascolormapping;
2615 skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2617 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2618 //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]);
2623 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2627 unsigned char *skindata;
2630 if (!skinframe->qpixels)
2633 if (!skinframe->qhascolormapping)
2634 colormapped = false;
2638 if (!skinframe->qgeneratebase)
2643 if (!skinframe->qgeneratemerged)
2647 width = skinframe->qwidth;
2648 height = skinframe->qheight;
2649 skindata = skinframe->qpixels;
2651 if (skinframe->qgeneratenmap)
2653 unsigned char *a, *b;
2654 skinframe->qgeneratenmap = false;
2655 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2656 b = a + width * height * 4;
2657 // use either a custom palette or the quake palette
2658 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2659 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2660 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);
2664 if (skinframe->qgenerateglow)
2666 skinframe->qgenerateglow = false;
2667 if (skinframe->hasalpha) // fence textures
2668 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
2670 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
2675 skinframe->qgeneratebase = false;
2676 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);
2677 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);
2678 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);
2682 skinframe->qgeneratemerged = false;
2683 if (skinframe->hasalpha) // fence textures
2684 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);
2686 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);
2689 if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2691 Mem_Free(skinframe->qpixels);
2692 skinframe->qpixels = NULL;
2696 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)
2699 skinframe_t *skinframe;
2702 if (cls.state == ca_dedicated)
2705 // if already loaded just return it, otherwise make a new skinframe
2706 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2707 if (skinframe->base)
2709 textureflags &= ~TEXF_FORCE_RELOAD;
2711 skinframe->stain = NULL;
2712 skinframe->merged = NULL;
2713 skinframe->base = NULL;
2714 skinframe->pants = NULL;
2715 skinframe->shirt = NULL;
2716 skinframe->nmap = NULL;
2717 skinframe->gloss = NULL;
2718 skinframe->glow = NULL;
2719 skinframe->fog = NULL;
2720 skinframe->reflect = NULL;
2721 skinframe->hasalpha = false;
2723 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2727 if (developer_loading.integer)
2728 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2730 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2731 if ((textureflags & TEXF_ALPHA) && alphapalette)
2733 for (i = 0;i < width * height;i++)
2735 if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2737 skinframe->hasalpha = true;
2741 if (r_loadfog && skinframe->hasalpha)
2742 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2745 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2746 //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]);
2751 skinframe_t *R_SkinFrame_LoadMissing(void)
2753 skinframe_t *skinframe;
2755 if (cls.state == ca_dedicated)
2758 skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2759 skinframe->stain = NULL;
2760 skinframe->merged = NULL;
2761 skinframe->base = NULL;
2762 skinframe->pants = NULL;
2763 skinframe->shirt = NULL;
2764 skinframe->nmap = NULL;
2765 skinframe->gloss = NULL;
2766 skinframe->glow = NULL;
2767 skinframe->fog = NULL;
2768 skinframe->reflect = NULL;
2769 skinframe->hasalpha = false;
2771 skinframe->avgcolor[0] = rand() / RAND_MAX;
2772 skinframe->avgcolor[1] = rand() / RAND_MAX;
2773 skinframe->avgcolor[2] = rand() / RAND_MAX;
2774 skinframe->avgcolor[3] = 1;
2779 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2782 static unsigned char pix[16][16][4];
2784 if (cls.state == ca_dedicated)
2787 // this makes a light grey/dark grey checkerboard texture
2790 for (y = 0; y < 16; y++)
2792 for (x = 0; x < 16; x++)
2794 if ((y < 8) ^ (x < 8))
2812 return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2815 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2817 skinframe_t *skinframe;
2818 if (cls.state == ca_dedicated)
2820 // if already loaded just return it, otherwise make a new skinframe
2821 skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2822 if (skinframe->base)
2824 textureflags &= ~TEXF_FORCE_RELOAD;
2825 skinframe->stain = NULL;
2826 skinframe->merged = NULL;
2827 skinframe->base = NULL;
2828 skinframe->pants = NULL;
2829 skinframe->shirt = NULL;
2830 skinframe->nmap = NULL;
2831 skinframe->gloss = NULL;
2832 skinframe->glow = NULL;
2833 skinframe->fog = NULL;
2834 skinframe->reflect = NULL;
2835 skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2836 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2839 if (developer_loading.integer)
2840 Con_Printf("loading 32bit skin \"%s\"\n", name);
2841 skinframe->base = skinframe->merged = tex;
2842 Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2846 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2847 typedef struct suffixinfo_s
2850 qboolean flipx, flipy, flipdiagonal;
2853 static suffixinfo_t suffix[3][6] =
2856 {"px", false, false, false},
2857 {"nx", false, false, false},
2858 {"py", false, false, false},
2859 {"ny", false, false, false},
2860 {"pz", false, false, false},
2861 {"nz", false, false, false}
2864 {"posx", false, false, false},
2865 {"negx", false, false, false},
2866 {"posy", false, false, false},
2867 {"negy", false, false, false},
2868 {"posz", false, false, false},
2869 {"negz", false, false, false}
2872 {"rt", true, false, true},
2873 {"lf", false, true, true},
2874 {"ft", true, true, false},
2875 {"bk", false, false, false},
2876 {"up", true, false, true},
2877 {"dn", true, false, true}
2881 static int componentorder[4] = {0, 1, 2, 3};
2883 static rtexture_t *R_LoadCubemap(const char *basename)
2885 int i, j, cubemapsize;
2886 unsigned char *cubemappixels, *image_buffer;
2887 rtexture_t *cubemaptexture;
2889 // must start 0 so the first loadimagepixels has no requested width/height
2891 cubemappixels = NULL;
2892 cubemaptexture = NULL;
2893 // keep trying different suffix groups (posx, px, rt) until one loads
2894 for (j = 0;j < 3 && !cubemappixels;j++)
2896 // load the 6 images in the suffix group
2897 for (i = 0;i < 6;i++)
2899 // generate an image name based on the base and and suffix
2900 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2902 if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2904 // an image loaded, make sure width and height are equal
2905 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2907 // if this is the first image to load successfully, allocate the cubemap memory
2908 if (!cubemappixels && image_width >= 1)
2910 cubemapsize = image_width;
2911 // note this clears to black, so unavailable sides are black
2912 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2914 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2916 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);
2919 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2921 Mem_Free(image_buffer);
2925 // if a cubemap loaded, upload it
2928 if (developer_loading.integer)
2929 Con_Printf("loading cubemap \"%s\"\n", basename);
2931 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);
2932 Mem_Free(cubemappixels);
2936 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2937 if (developer_loading.integer)
2939 Con_Printf("(tried tried images ");
2940 for (j = 0;j < 3;j++)
2941 for (i = 0;i < 6;i++)
2942 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2943 Con_Print(" and was unable to find any of them).\n");
2946 return cubemaptexture;
2949 rtexture_t *R_GetCubemap(const char *basename)
2952 for (i = 0;i < r_texture_numcubemaps;i++)
2953 if (r_texture_cubemaps[i] != NULL)
2954 if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2955 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2956 if (i >= MAX_CUBEMAPS || !r_main_mempool)
2957 return r_texture_whitecube;
2958 r_texture_numcubemaps++;
2959 r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2960 strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2961 r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2962 return r_texture_cubemaps[i]->texture;
2965 static void R_Main_FreeViewCache(void)
2967 if (r_refdef.viewcache.entityvisible)
2968 Mem_Free(r_refdef.viewcache.entityvisible);
2969 if (r_refdef.viewcache.world_pvsbits)
2970 Mem_Free(r_refdef.viewcache.world_pvsbits);
2971 if (r_refdef.viewcache.world_leafvisible)
2972 Mem_Free(r_refdef.viewcache.world_leafvisible);
2973 if (r_refdef.viewcache.world_surfacevisible)
2974 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2975 memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2978 static void R_Main_ResizeViewCache(void)
2980 int numentities = r_refdef.scene.numentities;
2981 int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2982 int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2983 int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2984 int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2985 if (r_refdef.viewcache.maxentities < numentities)
2987 r_refdef.viewcache.maxentities = numentities;
2988 if (r_refdef.viewcache.entityvisible)
2989 Mem_Free(r_refdef.viewcache.entityvisible);
2990 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2992 if (r_refdef.viewcache.world_numclusters != numclusters)
2994 r_refdef.viewcache.world_numclusters = numclusters;
2995 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2996 if (r_refdef.viewcache.world_pvsbits)
2997 Mem_Free(r_refdef.viewcache.world_pvsbits);
2998 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3000 if (r_refdef.viewcache.world_numleafs != numleafs)
3002 r_refdef.viewcache.world_numleafs = numleafs;
3003 if (r_refdef.viewcache.world_leafvisible)
3004 Mem_Free(r_refdef.viewcache.world_leafvisible);
3005 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3007 if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3009 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3010 if (r_refdef.viewcache.world_surfacevisible)
3011 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3012 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3016 extern rtexture_t *loadingscreentexture;
3017 static void gl_main_start(void)
3019 loadingscreentexture = NULL;
3020 r_texture_blanknormalmap = NULL;
3021 r_texture_white = NULL;
3022 r_texture_grey128 = NULL;
3023 r_texture_black = NULL;
3024 r_texture_whitecube = NULL;
3025 r_texture_normalizationcube = NULL;
3026 r_texture_fogattenuation = NULL;
3027 r_texture_fogheighttexture = NULL;
3028 r_texture_gammaramps = NULL;
3029 r_texture_numcubemaps = 0;
3030 r_uniformbufferalignment = 32;
3032 r_loaddds = r_texture_dds_load.integer != 0;
3033 r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3035 switch(vid.renderpath)
3037 case RENDERPATH_GL32:
3038 case RENDERPATH_GLES2:
3039 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3040 Cvar_SetValueQuick(&gl_combine, 1);
3041 Cvar_SetValueQuick(&r_glsl, 1);
3042 r_loadnormalmap = true;
3045 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3046 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3052 R_FrameData_Reset();
3053 R_BufferData_Reset();
3057 memset(r_queries, 0, sizeof(r_queries));
3059 r_qwskincache = NULL;
3060 r_qwskincache_size = 0;
3062 // due to caching of texture_t references, the collision cache must be reset
3063 Collision_Cache_Reset(true);
3065 // set up r_skinframe loading system for textures
3066 memset(&r_skinframe, 0, sizeof(r_skinframe));
3067 r_skinframe.loadsequence = 1;
3068 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3070 r_main_texturepool = R_AllocTexturePool();
3071 R_BuildBlankTextures();
3074 R_BuildNormalizationCube();
3075 r_texture_fogattenuation = NULL;
3076 r_texture_fogheighttexture = NULL;
3077 r_texture_gammaramps = NULL;
3078 //r_texture_fogintensity = NULL;
3079 memset(&r_fb, 0, sizeof(r_fb));
3080 Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3081 r_glsl_permutation = NULL;
3082 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3083 Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3084 memset(&r_svbsp, 0, sizeof (r_svbsp));
3086 memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3087 r_texture_numcubemaps = 0;
3089 r_refdef.fogmasktable_density = 0;
3092 // For Steelstorm Android
3093 // FIXME CACHE the program and reload
3094 // FIXME see possible combinations for SS:BR android
3095 Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3096 R_SetupShader_SetPermutationGLSL(0, 12);
3097 R_SetupShader_SetPermutationGLSL(0, 13);
3098 R_SetupShader_SetPermutationGLSL(0, 8388621);
3099 R_SetupShader_SetPermutationGLSL(3, 0);
3100 R_SetupShader_SetPermutationGLSL(3, 2048);
3101 R_SetupShader_SetPermutationGLSL(5, 0);
3102 R_SetupShader_SetPermutationGLSL(5, 2);
3103 R_SetupShader_SetPermutationGLSL(5, 2048);
3104 R_SetupShader_SetPermutationGLSL(5, 8388608);
3105 R_SetupShader_SetPermutationGLSL(11, 1);
3106 R_SetupShader_SetPermutationGLSL(11, 2049);
3107 R_SetupShader_SetPermutationGLSL(11, 8193);
3108 R_SetupShader_SetPermutationGLSL(11, 10241);
3109 Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3113 static void gl_main_shutdown(void)
3115 R_RenderTarget_FreeUnused(true);
3116 Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3118 R_FrameData_Reset();
3119 R_BufferData_Reset();
3121 R_Main_FreeViewCache();
3123 switch(vid.renderpath)
3125 case RENDERPATH_GL32:
3126 case RENDERPATH_GLES2:
3127 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3129 qglDeleteQueriesARB(r_maxqueries, r_queries);
3136 memset(r_queries, 0, sizeof(r_queries));
3138 r_qwskincache = NULL;
3139 r_qwskincache_size = 0;
3141 // clear out the r_skinframe state
3142 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3143 memset(&r_skinframe, 0, sizeof(r_skinframe));
3146 Mem_Free(r_svbsp.nodes);
3147 memset(&r_svbsp, 0, sizeof (r_svbsp));
3148 R_FreeTexturePool(&r_main_texturepool);
3149 loadingscreentexture = NULL;
3150 r_texture_blanknormalmap = NULL;
3151 r_texture_white = NULL;
3152 r_texture_grey128 = NULL;
3153 r_texture_black = NULL;
3154 r_texture_whitecube = NULL;
3155 r_texture_normalizationcube = NULL;
3156 r_texture_fogattenuation = NULL;
3157 r_texture_fogheighttexture = NULL;
3158 r_texture_gammaramps = NULL;
3159 r_texture_numcubemaps = 0;
3160 //r_texture_fogintensity = NULL;
3161 memset(&r_fb, 0, sizeof(r_fb));
3164 r_glsl_permutation = NULL;
3165 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3166 Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3169 static void gl_main_newmap(void)
3171 // FIXME: move this code to client
3172 char *entities, entname[MAX_QPATH];
3174 Mem_Free(r_qwskincache);
3175 r_qwskincache = NULL;
3176 r_qwskincache_size = 0;
3179 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3180 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3182 CL_ParseEntityLump(entities);
3186 if (cl.worldmodel->brush.entities)
3187 CL_ParseEntityLump(cl.worldmodel->brush.entities);
3189 R_Main_FreeViewCache();
3191 R_FrameData_Reset();
3192 R_BufferData_Reset();
3195 void GL_Main_Init(void)
3198 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3199 R_InitShaderModeInfo();
3201 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3202 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3203 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3204 if (gamemode == GAME_NEHAHRA)
3206 Cvar_RegisterVariable (&gl_fogenable);
3207 Cvar_RegisterVariable (&gl_fogdensity);
3208 Cvar_RegisterVariable (&gl_fogred);
3209 Cvar_RegisterVariable (&gl_foggreen);
3210 Cvar_RegisterVariable (&gl_fogblue);
3211 Cvar_RegisterVariable (&gl_fogstart);
3212 Cvar_RegisterVariable (&gl_fogend);
3213 Cvar_RegisterVariable (&gl_skyclip);
3215 Cvar_RegisterVariable(&r_motionblur);
3216 Cvar_RegisterVariable(&r_damageblur);
3217 Cvar_RegisterVariable(&r_motionblur_averaging);
3218 Cvar_RegisterVariable(&r_motionblur_randomize);
3219 Cvar_RegisterVariable(&r_motionblur_minblur);
3220 Cvar_RegisterVariable(&r_motionblur_maxblur);
3221 Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3222 Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3223 Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3224 Cvar_RegisterVariable(&r_motionblur_mousefactor);
3225 Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3226 Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3227 Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3228 Cvar_RegisterVariable(&r_equalize_entities_minambient);
3229 Cvar_RegisterVariable(&r_equalize_entities_by);
3230 Cvar_RegisterVariable(&r_equalize_entities_to);
3231 Cvar_RegisterVariable(&r_depthfirst);
3232 Cvar_RegisterVariable(&r_useinfinitefarclip);
3233 Cvar_RegisterVariable(&r_farclip_base);
3234 Cvar_RegisterVariable(&r_farclip_world);
3235 Cvar_RegisterVariable(&r_nearclip);
3236 Cvar_RegisterVariable(&r_deformvertexes);
3237 Cvar_RegisterVariable(&r_transparent);
3238 Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3239 Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3240 Cvar_RegisterVariable(&r_transparent_useplanardistance);
3241 Cvar_RegisterVariable(&r_showoverdraw);
3242 Cvar_RegisterVariable(&r_showbboxes);
3243 Cvar_RegisterVariable(&r_showbboxes_client);
3244 Cvar_RegisterVariable(&r_showsurfaces);
3245 Cvar_RegisterVariable(&r_showtris);
3246 Cvar_RegisterVariable(&r_shownormals);
3247 Cvar_RegisterVariable(&r_showlighting);
3248 Cvar_RegisterVariable(&r_showcollisionbrushes);
3249 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3250 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3251 Cvar_RegisterVariable(&r_showdisabledepthtest);
3252 Cvar_RegisterVariable(&r_showspriteedges);
3253 Cvar_RegisterVariable(&r_showparticleedges);
3254 Cvar_RegisterVariable(&r_drawportals);
3255 Cvar_RegisterVariable(&r_drawentities);
3256 Cvar_RegisterVariable(&r_draw2d);
3257 Cvar_RegisterVariable(&r_drawworld);
3258 Cvar_RegisterVariable(&r_cullentities_trace);
3259 Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3260 Cvar_RegisterVariable(&r_cullentities_trace_samples);
3261 Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3262 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3263 Cvar_RegisterVariable(&r_cullentities_trace_expand);
3264 Cvar_RegisterVariable(&r_cullentities_trace_pad);
3265 Cvar_RegisterVariable(&r_cullentities_trace_delay);
3266 Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3267 Cvar_RegisterVariable(&r_sortentities);
3268 Cvar_RegisterVariable(&r_drawviewmodel);
3269 Cvar_RegisterVariable(&r_drawexteriormodel);
3270 Cvar_RegisterVariable(&r_speeds);
3271 Cvar_RegisterVariable(&r_fullbrights);
3272 Cvar_RegisterVariable(&r_wateralpha);
3273 Cvar_RegisterVariable(&r_dynamic);
3274 Cvar_RegisterVariable(&r_fakelight);
3275 Cvar_RegisterVariable(&r_fakelight_intensity);
3276 Cvar_RegisterVariable(&r_fullbright_directed);
3277 Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3278 Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3279 Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3280 Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3281 Cvar_RegisterVariable(&r_fullbright);
3282 Cvar_RegisterVariable(&r_shadows);
3283 Cvar_RegisterVariable(&r_shadows_darken);
3284 Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3285 Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3286 Cvar_RegisterVariable(&r_shadows_throwdistance);
3287 Cvar_RegisterVariable(&r_shadows_throwdirection);
3288 Cvar_RegisterVariable(&r_shadows_focus);
3289 Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3290 Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3291 Cvar_RegisterVariable(&r_q1bsp_skymasking);
3292 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3293 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3294 Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3295 Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3296 Cvar_RegisterVariable(&r_fog_exp2);
3297 Cvar_RegisterVariable(&r_fog_clear);
3298 Cvar_RegisterVariable(&r_drawfog);
3299 Cvar_RegisterVariable(&r_transparentdepthmasking);
3300 Cvar_RegisterVariable(&r_transparent_sortmindist);
3301 Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3302 Cvar_RegisterVariable(&r_transparent_sortarraysize);
3303 Cvar_RegisterVariable(&r_texture_dds_load);
3304 Cvar_RegisterVariable(&r_texture_dds_save);
3305 Cvar_RegisterVariable(&r_textureunits);
3306 Cvar_RegisterVariable(&gl_combine);
3307 Cvar_RegisterVariable(&r_usedepthtextures);
3308 Cvar_RegisterVariable(&r_viewfbo);
3309 Cvar_RegisterVariable(&r_rendertarget_debug);
3310 Cvar_RegisterVariable(&r_viewscale);
3311 Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3312 Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3313 Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3314 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3315 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3316 Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3317 Cvar_RegisterVariable(&r_glsl);
3318 Cvar_RegisterVariable(&r_glsl_deluxemapping);
3319 Cvar_RegisterVariable(&r_glsl_offsetmapping);
3320 Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3321 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3322 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3323 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3324 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3325 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3326 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3327 Cvar_RegisterVariable(&r_glsl_postprocess);
3328 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3329 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3330 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3331 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3332 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3333 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3334 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3335 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3336 Cvar_RegisterVariable(&r_celshading);
3337 Cvar_RegisterVariable(&r_celoutlines);
3339 Cvar_RegisterVariable(&r_water);
3340 Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3341 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3342 Cvar_RegisterVariable(&r_water_clippingplanebias);
3343 Cvar_RegisterVariable(&r_water_refractdistort);
3344 Cvar_RegisterVariable(&r_water_reflectdistort);
3345 Cvar_RegisterVariable(&r_water_scissormode);
3346 Cvar_RegisterVariable(&r_water_lowquality);
3347 Cvar_RegisterVariable(&r_water_hideplayer);
3349 Cvar_RegisterVariable(&r_lerpsprites);
3350 Cvar_RegisterVariable(&r_lerpmodels);
3351 Cvar_RegisterVariable(&r_lerplightstyles);
3352 Cvar_RegisterVariable(&r_waterscroll);
3353 Cvar_RegisterVariable(&r_bloom);
3354 Cvar_RegisterVariable(&r_bloom_colorscale);
3355 Cvar_RegisterVariable(&r_bloom_brighten);
3356 Cvar_RegisterVariable(&r_bloom_blur);
3357 Cvar_RegisterVariable(&r_bloom_resolution);
3358 Cvar_RegisterVariable(&r_bloom_colorexponent);
3359 Cvar_RegisterVariable(&r_bloom_colorsubtract);
3360 Cvar_RegisterVariable(&r_bloom_scenebrightness);
3361 Cvar_RegisterVariable(&r_hdr_scenebrightness);
3362 Cvar_RegisterVariable(&r_hdr_glowintensity);
3363 Cvar_RegisterVariable(&r_hdr_irisadaptation);
3364 Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3365 Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3366 Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3367 Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3368 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3369 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3370 Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3371 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3372 Cvar_RegisterVariable(&developer_texturelogging);
3373 Cvar_RegisterVariable(&gl_lightmaps);
3374 Cvar_RegisterVariable(&r_test);
3375 Cvar_RegisterVariable(&r_batch_multidraw);
3376 Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3377 Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3378 Cvar_RegisterVariable(&r_glsl_skeletal);
3379 Cvar_RegisterVariable(&r_glsl_saturation);
3380 Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3381 Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3382 Cvar_RegisterVariable(&r_framedatasize);
3383 for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3384 Cvar_RegisterVariable(&r_buffermegs[i]);
3385 Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3386 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3387 Cvar_SetValue("r_fullbrights", 0);
3388 #ifdef DP_MOBILETOUCH
3389 // GLES devices have terrible depth precision in general, so...
3390 Cvar_SetValueQuick(&r_nearclip, 4);
3391 Cvar_SetValueQuick(&r_farclip_base, 4096);
3392 Cvar_SetValueQuick(&r_farclip_world, 0);
3393 Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3395 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3398 void Render_Init(void)
3411 R_LightningBeams_Init();
3421 extern char *ENGINE_EXTENSIONS;
3424 gl_renderer = (const char *)qglGetString(GL_RENDERER);
3425 gl_vendor = (const char *)qglGetString(GL_VENDOR);
3426 gl_version = (const char *)qglGetString(GL_VERSION);
3427 gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3431 if (!gl_platformextensions)
3432 gl_platformextensions = "";
3434 Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3435 Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3436 Con_Printf("GL_VERSION: %s\n", gl_version);
3437 Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3438 Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3440 VID_CheckExtensions();
3442 // LordHavoc: report supported extensions
3444 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3446 Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3449 // clear to black (loading plaque will be seen over this)
3450 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
3454 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3458 if (r_trippy.integer)
3460 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3462 p = r_refdef.view.frustum + i;
3467 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3471 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3475 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3479 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3483 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3487 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3491 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3495 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3503 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3507 if (r_trippy.integer)
3509 for (i = 0;i < numplanes;i++)
3516 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3520 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3524 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3528 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3532 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3536 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3540 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3544 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3552 //==================================================================================
3554 // LordHavoc: this stores temporary data used within the same frame
3556 typedef struct r_framedata_mem_s
3558 struct r_framedata_mem_s *purge; // older mem block to free on next frame
3559 size_t size; // how much usable space
3560 size_t current; // how much space in use
3561 size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3562 size_t wantedsize; // how much space was allocated
3563 unsigned char *data; // start of real data (16byte aligned)
3567 static r_framedata_mem_t *r_framedata_mem;
3569 void R_FrameData_Reset(void)
3571 while (r_framedata_mem)
3573 r_framedata_mem_t *next = r_framedata_mem->purge;
3574 Mem_Free(r_framedata_mem);
3575 r_framedata_mem = next;
3579 static void R_FrameData_Resize(qboolean mustgrow)
3582 wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3583 wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3584 if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3586 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3587 newmem->wantedsize = wantedsize;
3588 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3589 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3590 newmem->current = 0;
3592 newmem->purge = r_framedata_mem;
3593 r_framedata_mem = newmem;
3597 void R_FrameData_NewFrame(void)
3599 R_FrameData_Resize(false);
3600 if (!r_framedata_mem)
3602 // if we ran out of space on the last frame, free the old memory now
3603 while (r_framedata_mem->purge)
3605 // repeatedly remove the second item in the list, leaving only head
3606 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3607 Mem_Free(r_framedata_mem->purge);
3608 r_framedata_mem->purge = next;
3610 // reset the current mem pointer
3611 r_framedata_mem->current = 0;
3612 r_framedata_mem->mark = 0;
3615 void *R_FrameData_Alloc(size_t size)
3620 // align to 16 byte boundary - the data pointer is already aligned, so we
3621 // only need to ensure the size of every allocation is also aligned
3622 size = (size + 15) & ~15;
3624 while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3626 // emergency - we ran out of space, allocate more memory
3627 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3628 newvalue = r_framedatasize.value * 2.0f;
3629 // 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
3630 if (sizeof(size_t) >= 8)
3631 newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3633 newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3634 // this might not be a growing it, but we'll allocate another buffer every time
3635 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3636 R_FrameData_Resize(true);
3639 data = r_framedata_mem->data + r_framedata_mem->current;
3640 r_framedata_mem->current += size;
3642 // count the usage for stats
3643 r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3644 r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3646 return (void *)data;
3649 void *R_FrameData_Store(size_t size, void *data)
3651 void *d = R_FrameData_Alloc(size);
3653 memcpy(d, data, size);
3657 void R_FrameData_SetMark(void)
3659 if (!r_framedata_mem)
3661 r_framedata_mem->mark = r_framedata_mem->current;
3664 void R_FrameData_ReturnToMark(void)
3666 if (!r_framedata_mem)
3668 r_framedata_mem->current = r_framedata_mem->mark;
3671 //==================================================================================
3673 // avoid reusing the same buffer objects on consecutive frames
3674 #define R_BUFFERDATA_CYCLE 3
3676 typedef struct r_bufferdata_buffer_s
3678 struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3679 size_t size; // how much usable space
3680 size_t current; // how much space in use
3681 r_meshbuffer_t *buffer; // the buffer itself
3683 r_bufferdata_buffer_t;
3685 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3686 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3688 /// frees all dynamic buffers
3689 void R_BufferData_Reset(void)
3692 r_bufferdata_buffer_t **p, *mem;
3693 for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3695 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3698 p = &r_bufferdata_buffer[cycle][type];
3704 R_Mesh_DestroyMeshBuffer(mem->buffer);
3711 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3712 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3714 r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3716 float newvalue = r_buffermegs[type].value;
3718 // increase the cvar if we have to (but only if we already have a mem)
3719 if (mustgrow && mem)
3721 newvalue = bound(0.25f, newvalue, 256.0f);
3722 while (newvalue * 1024*1024 < minsize)
3725 // clamp the cvar to valid range
3726 newvalue = bound(0.25f, newvalue, 256.0f);
3727 if (r_buffermegs[type].value != newvalue)
3728 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3730 // calculate size in bytes
3731 size = (size_t)(newvalue * 1024*1024);
3732 size = bound(131072, size, 256*1024*1024);
3734 // allocate a new buffer if the size is different (purge old one later)
3735 // or if we were told we must grow the buffer
3736 if (!mem || mem->size != size || mustgrow)
3738 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3741 if (type == R_BUFFERDATA_VERTEX)
3742 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3743 else if (type == R_BUFFERDATA_INDEX16)
3744 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3745 else if (type == R_BUFFERDATA_INDEX32)
3746 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3747 else if (type == R_BUFFERDATA_UNIFORM)
3748 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3749 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3750 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3754 void R_BufferData_NewFrame(void)
3757 r_bufferdata_buffer_t **p, *mem;
3758 // cycle to the next frame's buffers
3759 r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3760 // if we ran out of space on the last time we used these buffers, free the old memory now
3761 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3763 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3765 R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3766 // free all but the head buffer, this is how we recycle obsolete
3767 // buffers after they are no longer in use
3768 p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3774 R_Mesh_DestroyMeshBuffer(mem->buffer);
3777 // reset the current offset
3778 r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3783 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3785 r_bufferdata_buffer_t *mem;
3789 *returnbufferoffset = 0;
3791 // align size to a byte boundary appropriate for the buffer type, this
3792 // makes all allocations have aligned start offsets
3793 if (type == R_BUFFERDATA_UNIFORM)
3794 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3796 padsize = (datasize + 15) & ~15;
3798 // if we ran out of space in this buffer we must allocate a new one
3799 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)
3800 R_BufferData_Resize(type, true, padsize);
3802 // if the resize did not give us enough memory, fail
3803 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)
3804 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3806 mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3807 offset = (int)mem->current;
3808 mem->current += padsize;
3810 // upload the data to the buffer at the chosen offset
3812 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3813 R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3815 // count the usage for stats
3816 r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3817 r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3819 // return the buffer offset
3820 *returnbufferoffset = offset;
3825 //==================================================================================
3827 // LordHavoc: animcache originally written by Echon, rewritten since then
3830 * Animation cache prevents re-generating mesh data for an animated model
3831 * multiple times in one frame for lighting, shadowing, reflections, etc.
3834 void R_AnimCache_Free(void)
3838 void R_AnimCache_ClearCache(void)
3841 entity_render_t *ent;
3843 for (i = 0;i < r_refdef.scene.numentities;i++)
3845 ent = r_refdef.scene.entities[i];
3846 ent->animcache_vertex3f = NULL;
3847 ent->animcache_vertex3f_vertexbuffer = NULL;
3848 ent->animcache_vertex3f_bufferoffset = 0;
3849 ent->animcache_normal3f = NULL;
3850 ent->animcache_normal3f_vertexbuffer = NULL;
3851 ent->animcache_normal3f_bufferoffset = 0;
3852 ent->animcache_svector3f = NULL;
3853 ent->animcache_svector3f_vertexbuffer = NULL;
3854 ent->animcache_svector3f_bufferoffset = 0;
3855 ent->animcache_tvector3f = NULL;
3856 ent->animcache_tvector3f_vertexbuffer = NULL;
3857 ent->animcache_tvector3f_bufferoffset = 0;
3858 ent->animcache_skeletaltransform3x4 = NULL;
3859 ent->animcache_skeletaltransform3x4buffer = NULL;
3860 ent->animcache_skeletaltransform3x4offset = 0;
3861 ent->animcache_skeletaltransform3x4size = 0;
3865 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3867 dp_model_t *model = ent->model;
3870 // see if this ent is worth caching
3871 if (!model || !model->Draw || !model->AnimateVertices)
3873 // nothing to cache if it contains no animations and has no skeleton
3874 if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3876 // see if it is already cached for gpuskeletal
3877 if (ent->animcache_skeletaltransform3x4)
3879 // see if it is already cached as a mesh
3880 if (ent->animcache_vertex3f)
3882 // check if we need to add normals or tangents
3883 if (ent->animcache_normal3f)
3884 wantnormals = false;
3885 if (ent->animcache_svector3f)
3886 wanttangents = false;
3887 if (!wantnormals && !wanttangents)
3891 // check which kind of cache we need to generate
3892 if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3894 // cache the skeleton so the vertex shader can use it
3895 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3896 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3897 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3898 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3899 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3900 // note: this can fail if the buffer is at the grow limit
3901 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3902 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3904 else if (ent->animcache_vertex3f)
3906 // mesh was already cached but we may need to add normals/tangents
3907 // (this only happens with multiple views, reflections, cameras, etc)
3908 if (wantnormals || wanttangents)
3910 numvertices = model->surfmesh.num_vertices;
3912 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3915 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3916 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3918 model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3919 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3920 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3921 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3926 // generate mesh cache
3927 numvertices = model->surfmesh.num_vertices;
3928 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3930 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3933 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3934 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3936 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3937 if (wantnormals || wanttangents)
3939 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3940 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3941 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3943 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3944 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3945 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3950 void R_AnimCache_CacheVisibleEntities(void)
3954 // TODO: thread this
3955 // NOTE: R_PrepareRTLights() also caches entities
3957 for (i = 0;i < r_refdef.scene.numentities;i++)
3958 if (r_refdef.viewcache.entityvisible[i])
3959 R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3962 //==================================================================================
3964 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)
3967 vec3_t eyemins, eyemaxs;
3968 vec3_t boxmins, boxmaxs;
3969 vec3_t padmins, padmaxs;
3972 dp_model_t *model = r_refdef.scene.worldmodel;
3973 static vec3_t positions[] = {
3974 { 0.5f, 0.5f, 0.5f },
3975 { 0.0f, 0.0f, 0.0f },
3976 { 0.0f, 0.0f, 1.0f },
3977 { 0.0f, 1.0f, 0.0f },
3978 { 0.0f, 1.0f, 1.0f },
3979 { 1.0f, 0.0f, 0.0f },
3980 { 1.0f, 0.0f, 1.0f },
3981 { 1.0f, 1.0f, 0.0f },
3982 { 1.0f, 1.0f, 1.0f },
3985 // sample count can be set to -1 to skip this logic, for flicker-prone objects
3989 // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3990 if (!r_refdef.view.usevieworiginculling)
3993 if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3996 // expand the eye box a little
3997 eyemins[0] = eye[0] - eyejitter;
3998 eyemaxs[0] = eye[0] + eyejitter;
3999 eyemins[1] = eye[1] - eyejitter;
4000 eyemaxs[1] = eye[1] + eyejitter;
4001 eyemins[2] = eye[2] - eyejitter;
4002 eyemaxs[2] = eye[2] + eyejitter;
4003 // expand the box a little
4004 boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4005 boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4006 boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4007 boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4008 boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4009 boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4010 // make an even larger box for the acceptable area
4011 padmins[0] = boxmins[0] - pad;
4012 padmaxs[0] = boxmaxs[0] + pad;
4013 padmins[1] = boxmins[1] - pad;
4014 padmaxs[1] = boxmaxs[1] + pad;
4015 padmins[2] = boxmins[2] - pad;
4016 padmaxs[2] = boxmaxs[2] + pad;
4018 // return true if eye overlaps enlarged box
4019 if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4022 // try specific positions in the box first - note that these can be cached
4023 if (r_cullentities_trace_entityocclusion.integer)
4025 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4027 VectorCopy(eye, start);
4028 end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4029 end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4030 end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4031 //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4032 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4033 // not picky - if the trace ended anywhere in the box we're good
4034 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4038 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4041 // try various random positions
4042 for (i = 0; i < numsamples; i++)
4044 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4045 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4046 if (r_cullentities_trace_entityocclusion.integer)
4048 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4049 // not picky - if the trace ended anywhere in the box we're good
4050 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4053 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4061 static void R_View_UpdateEntityVisible (void)
4066 entity_render_t *ent;
4068 if (r_refdef.envmap || r_fb.water.hideplayer)
4069 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4070 else if (chase_active.integer || r_fb.water.renderingscene)
4071 renderimask = RENDER_VIEWMODEL;
4073 renderimask = RENDER_EXTERIORMODEL;
4074 if (!r_drawviewmodel.integer)
4075 renderimask |= RENDER_VIEWMODEL;
4076 if (!r_drawexteriormodel.integer)
4077 renderimask |= RENDER_EXTERIORMODEL;
4078 memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4079 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4081 // worldmodel can check visibility
4082 for (i = 0;i < r_refdef.scene.numentities;i++)
4084 ent = r_refdef.scene.entities[i];
4085 if (!(ent->flags & renderimask))
4086 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)))
4087 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))
4088 r_refdef.viewcache.entityvisible[i] = true;
4093 // no worldmodel or it can't check visibility
4094 for (i = 0;i < r_refdef.scene.numentities;i++)
4096 ent = r_refdef.scene.entities[i];
4097 if (!(ent->flags & renderimask))
4098 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)))
4099 r_refdef.viewcache.entityvisible[i] = true;
4102 if (r_cullentities_trace.integer)
4104 for (i = 0;i < r_refdef.scene.numentities;i++)
4106 if (!r_refdef.viewcache.entityvisible[i])
4108 ent = r_refdef.scene.entities[i];
4109 if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4111 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4112 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))
4113 ent->last_trace_visibility = realtime;
4114 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4115 r_refdef.viewcache.entityvisible[i] = 0;
4121 /// only used if skyrendermasked, and normally returns false
4122 static int R_DrawBrushModelsSky (void)
4125 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->DrawSky)
4135 ent->model->DrawSky(ent);
4141 static void R_DrawNoModel(entity_render_t *ent);
4142 static void R_DrawModels(void)
4145 entity_render_t *ent;
4147 for (i = 0;i < r_refdef.scene.numentities;i++)
4149 if (!r_refdef.viewcache.entityvisible[i])
4151 ent = r_refdef.scene.entities[i];
4152 r_refdef.stats[r_stat_entities]++;
4154 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4157 Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4158 Con_Printf("R_DrawModels\n");
4159 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]);
4160 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);
4161 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);
4164 if (ent->model && ent->model->Draw != NULL)
4165 ent->model->Draw(ent);
4171 static void R_DrawModelsDepth(void)
4174 entity_render_t *ent;
4176 for (i = 0;i < r_refdef.scene.numentities;i++)
4178 if (!r_refdef.viewcache.entityvisible[i])
4180 ent = r_refdef.scene.entities[i];
4181 if (ent->model && ent->model->DrawDepth != NULL)
4182 ent->model->DrawDepth(ent);
4186 static void R_DrawModelsDebug(void)
4189 entity_render_t *ent;
4191 for (i = 0;i < r_refdef.scene.numentities;i++)
4193 if (!r_refdef.viewcache.entityvisible[i])
4195 ent = r_refdef.scene.entities[i];
4196 if (ent->model && ent->model->DrawDebug != NULL)
4197 ent->model->DrawDebug(ent);
4201 static void R_DrawModelsAddWaterPlanes(void)
4204 entity_render_t *ent;
4206 for (i = 0;i < r_refdef.scene.numentities;i++)
4208 if (!r_refdef.viewcache.entityvisible[i])
4210 ent = r_refdef.scene.entities[i];
4211 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4212 ent->model->DrawAddWaterPlanes(ent);
4216 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}};
4218 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4220 if (r_hdr_irisadaptation.integer)
4225 vec3_t diffusenormal;
4227 vec_t brightness = 0.0f;
4232 VectorCopy(r_refdef.view.forward, forward);
4233 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4235 p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4236 p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4237 p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4238 R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4239 d = DotProduct(forward, diffusenormal);
4240 brightness += VectorLength(ambient);
4242 brightness += d * VectorLength(diffuse);
4244 brightness *= 1.0f / c;
4245 brightness += 0.00001f; // make sure it's never zero
4246 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4247 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4248 current = r_hdr_irisadaptation_value.value;
4250 current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4251 else if (current > goal)
4252 current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4253 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4254 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4256 else if (r_hdr_irisadaptation_value.value != 1.0f)
4257 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4260 static void R_View_SetFrustum(const int *scissor)
4263 double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4264 vec3_t forward, left, up, origin, v;
4268 // flipped x coordinates (because x points left here)
4269 fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4270 fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4271 // non-flipped y coordinates
4272 fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4273 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4276 // we can't trust r_refdef.view.forward and friends in reflected scenes
4277 Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4280 r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4281 r_refdef.view.frustum[0].normal[1] = 0 - 0;
4282 r_refdef.view.frustum[0].normal[2] = -1 - 0;
4283 r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4284 r_refdef.view.frustum[1].normal[1] = 0 + 0;
4285 r_refdef.view.frustum[1].normal[2] = -1 + 0;
4286 r_refdef.view.frustum[2].normal[0] = 0 - 0;
4287 r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4288 r_refdef.view.frustum[2].normal[2] = -1 - 0;
4289 r_refdef.view.frustum[3].normal[0] = 0 + 0;
4290 r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4291 r_refdef.view.frustum[3].normal[2] = -1 + 0;
4295 zNear = r_refdef.nearclip;
4296 nudge = 1.0 - 1.0 / (1<<23);
4297 r_refdef.view.frustum[4].normal[0] = 0 - 0;
4298 r_refdef.view.frustum[4].normal[1] = 0 - 0;
4299 r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4300 r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4301 r_refdef.view.frustum[5].normal[0] = 0 + 0;
4302 r_refdef.view.frustum[5].normal[1] = 0 + 0;
4303 r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4304 r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4310 r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4311 r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4312 r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4313 r_refdef.view.frustum[0].dist = m[15] - m[12];
4315 r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4316 r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4317 r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4318 r_refdef.view.frustum[1].dist = m[15] + m[12];
4320 r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4321 r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4322 r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4323 r_refdef.view.frustum[2].dist = m[15] - m[13];
4325 r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4326 r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4327 r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4328 r_refdef.view.frustum[3].dist = m[15] + m[13];
4330 r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4331 r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4332 r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4333 r_refdef.view.frustum[4].dist = m[15] - m[14];
4335 r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4336 r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4337 r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4338 r_refdef.view.frustum[5].dist = m[15] + m[14];
4341 if (r_refdef.view.useperspective)
4343 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4344 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]);
4345 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]);
4346 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]);
4347 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]);
4349 // then the normals from the corners relative to origin
4350 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4351 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4352 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4353 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4355 // in a NORMAL view, forward cross left == up
4356 // in a REFLECTED view, forward cross left == down
4357 // so our cross products above need to be adjusted for a left handed coordinate system
4358 CrossProduct(forward, left, v);
4359 if(DotProduct(v, up) < 0)
4361 VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4362 VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4363 VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4364 VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4367 // Leaving those out was a mistake, those were in the old code, and they
4368 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4369 // I couldn't reproduce it after adding those normalizations. --blub
4370 VectorNormalize(r_refdef.view.frustum[0].normal);
4371 VectorNormalize(r_refdef.view.frustum[1].normal);
4372 VectorNormalize(r_refdef.view.frustum[2].normal);
4373 VectorNormalize(r_refdef.view.frustum[3].normal);
4375 // make the corners absolute
4376 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4377 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4378 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4379 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4382 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4384 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4385 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4386 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4387 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4388 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4392 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4393 VectorScale(left, 1.0f, r_refdef.view.frustum[1].normal);
4394 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4395 VectorScale(up, 1.0f, r_refdef.view.frustum[3].normal);
4396 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4397 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4398 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4399 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4400 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4401 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4403 r_refdef.view.numfrustumplanes = 5;
4405 if (r_refdef.view.useclipplane)
4407 r_refdef.view.numfrustumplanes = 6;
4408 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4411 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4412 PlaneClassify(r_refdef.view.frustum + i);
4414 // LordHavoc: note to all quake engine coders, Quake had a special case
4415 // for 90 degrees which assumed a square view (wrong), so I removed it,
4416 // Quake2 has it disabled as well.
4418 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4419 //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4420 //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4421 //PlaneClassify(&frustum[0]);
4423 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4424 //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4425 //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4426 //PlaneClassify(&frustum[1]);
4428 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4429 //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4430 //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4431 //PlaneClassify(&frustum[2]);
4433 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4434 //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4435 //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4436 //PlaneClassify(&frustum[3]);
4439 //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4440 //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4441 //PlaneClassify(&frustum[4]);
4444 static void R_View_UpdateWithScissor(const int *myscissor)
4446 R_Main_ResizeViewCache();
4447 R_View_SetFrustum(myscissor);
4448 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4449 R_View_UpdateEntityVisible();
4452 static void R_View_Update(void)
4454 R_Main_ResizeViewCache();
4455 R_View_SetFrustum(NULL);
4456 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4457 R_View_UpdateEntityVisible();
4460 float viewscalefpsadjusted = 1.0f;
4462 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4464 float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4465 scale = bound(0.03125f, scale, 1.0f);
4466 *outwidth = (int)ceil(width * scale);
4467 *outheight = (int)ceil(height * scale);
4470 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4472 const float *customclipplane = NULL;
4474 int /*rtwidth,*/ rtheight;
4475 if (r_refdef.view.useclipplane && allowwaterclippingplane)
4477 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4478 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4479 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4480 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4481 dist = r_refdef.view.clipplane.dist;
4482 plane[0] = r_refdef.view.clipplane.normal[0];
4483 plane[1] = r_refdef.view.clipplane.normal[1];
4484 plane[2] = r_refdef.view.clipplane.normal[2];
4486 customclipplane = plane;
4489 //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4490 rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4492 if (!r_refdef.view.useperspective)
4493 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);
4494 else if (vid.stencil && r_useinfinitefarclip.integer)
4495 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);
4497 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);
4498 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4499 R_SetViewport(&r_refdef.view.viewport);
4502 void R_EntityMatrix(const matrix4x4_t *matrix)
4504 if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4506 gl_modelmatrixchanged = false;
4507 gl_modelmatrix = *matrix;
4508 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4509 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4510 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4511 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4513 switch(vid.renderpath)
4515 case RENDERPATH_GL32:
4516 case RENDERPATH_GLES2:
4517 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4518 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4524 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4526 r_viewport_t viewport;
4530 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4531 R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4532 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4533 R_SetViewport(&viewport);
4534 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4535 GL_Color(1, 1, 1, 1);
4536 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4537 GL_BlendFunc(GL_ONE, GL_ZERO);
4538 GL_ScissorTest(false);
4539 GL_DepthMask(false);
4540 GL_DepthRange(0, 1);
4541 GL_DepthTest(false);
4542 GL_DepthFunc(GL_LEQUAL);
4543 R_EntityMatrix(&identitymatrix);
4544 R_Mesh_ResetTextureState();
4545 GL_PolygonOffset(0, 0);
4546 switch(vid.renderpath)
4548 case RENDERPATH_GL32:
4549 case RENDERPATH_GLES2:
4550 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4553 GL_CullFace(GL_NONE);
4558 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4560 R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4563 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4565 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4566 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4567 GL_Color(1, 1, 1, 1);
4568 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4569 GL_BlendFunc(GL_ONE, GL_ZERO);
4570 GL_ScissorTest(true);
4572 GL_DepthRange(0, 1);
4574 GL_DepthFunc(GL_LEQUAL);
4575 R_EntityMatrix(&identitymatrix);
4576 R_Mesh_ResetTextureState();
4577 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4578 switch(vid.renderpath)
4580 case RENDERPATH_GL32:
4581 case RENDERPATH_GLES2:
4582 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4585 GL_CullFace(r_refdef.view.cullface_back);
4590 R_RenderView_UpdateViewVectors
4593 void R_RenderView_UpdateViewVectors(void)
4595 // break apart the view matrix into vectors for various purposes
4596 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4597 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4598 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4599 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4600 // make an inverted copy of the view matrix for tracking sprites
4601 Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4604 void R_RenderTarget_FreeUnused(qboolean force)
4607 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4608 for (i = 0; i < end; i++)
4610 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4611 // free resources for rendertargets that have not been used for a while
4612 // (note: this check is run after the frame render, so any targets used
4613 // this frame will not be affected even at low framerates)
4614 if (r && (realtime - r->lastusetime > 0.2 || force))
4617 R_Mesh_DestroyFramebufferObject(r->fbo);
4618 for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4619 if (r->colortexture[j])
4620 R_FreeTexture(r->colortexture[j]);
4621 if (r->depthtexture)
4622 R_FreeTexture(r->depthtexture);
4623 Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4628 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4630 float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4634 y2 = (th - y - h) * ih;
4645 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)
4648 r_rendertarget_t *r = NULL;
4650 // first try to reuse an existing slot if possible
4651 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4652 for (i = 0; i < end; i++)
4654 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4655 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)
4660 // no unused exact match found, so we have to make one in the first unused slot
4661 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4662 r->texturewidth = texturewidth;
4663 r->textureheight = textureheight;
4664 r->colortextype[0] = colortextype0;
4665 r->colortextype[1] = colortextype1;
4666 r->colortextype[2] = colortextype2;
4667 r->colortextype[3] = colortextype3;
4668 r->depthtextype = depthtextype;
4669 r->depthisrenderbuffer = depthisrenderbuffer;
4670 for (j = 0; j < 4; j++)
4671 if (r->colortextype[j])
4672 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);
4673 if (r->depthtextype)
4675 if (r->depthisrenderbuffer)
4676 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);
4678 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);
4680 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4682 r_refdef.stats[r_stat_rendertargets_used]++;
4683 r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4684 r->lastusetime = realtime;
4685 R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4689 static void R_Water_StartFrame(void)
4691 int waterwidth, waterheight;
4693 if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4696 // set waterwidth and waterheight to the water resolution that will be
4697 // used (often less than the screen resolution for faster rendering)
4698 waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4699 waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4700 R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4702 if (!r_water.integer || r_showsurfaces.integer)
4703 waterwidth = waterheight = 0;
4705 // set up variables that will be used in shader setup
4706 r_fb.water.waterwidth = waterwidth;
4707 r_fb.water.waterheight = waterheight;
4708 r_fb.water.texturewidth = waterwidth;
4709 r_fb.water.textureheight = waterheight;
4710 r_fb.water.camerawidth = waterwidth;
4711 r_fb.water.cameraheight = waterheight;
4712 r_fb.water.screenscale[0] = 0.5f;
4713 r_fb.water.screenscale[1] = 0.5f;
4714 r_fb.water.screencenter[0] = 0.5f;
4715 r_fb.water.screencenter[1] = 0.5f;
4716 r_fb.water.enabled = waterwidth != 0;
4718 r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4719 r_fb.water.numwaterplanes = 0;
4722 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4724 int planeindex, bestplaneindex, vertexindex;
4725 vec3_t mins, maxs, normal, center, v, n;
4726 vec_t planescore, bestplanescore;
4728 r_waterstate_waterplane_t *p;
4729 texture_t *t = R_GetCurrentTexture(surface->texture);
4731 rsurface.texture = t;
4732 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4733 // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4734 if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4736 // average the vertex normals, find the surface bounds (after deformvertexes)
4737 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4738 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4739 VectorCopy(n, normal);
4740 VectorCopy(v, mins);
4741 VectorCopy(v, maxs);
4742 for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4744 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4745 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4746 VectorAdd(normal, n, normal);
4747 mins[0] = min(mins[0], v[0]);
4748 mins[1] = min(mins[1], v[1]);
4749 mins[2] = min(mins[2], v[2]);
4750 maxs[0] = max(maxs[0], v[0]);
4751 maxs[1] = max(maxs[1], v[1]);
4752 maxs[2] = max(maxs[2], v[2]);
4754 VectorNormalize(normal);
4755 VectorMAM(0.5f, mins, 0.5f, maxs, center);
4757 VectorCopy(normal, plane.normal);
4758 VectorNormalize(plane.normal);
4759 plane.dist = DotProduct(center, plane.normal);
4760 PlaneClassify(&plane);
4761 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4763 // skip backfaces (except if nocullface is set)
4764 // if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4766 VectorNegate(plane.normal, plane.normal);
4768 PlaneClassify(&plane);
4772 // find a matching plane if there is one
4773 bestplaneindex = -1;
4774 bestplanescore = 1048576.0f;
4775 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4777 if(p->camera_entity == t->camera_entity)
4779 planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4780 if (bestplaneindex < 0 || bestplanescore > planescore)
4782 bestplaneindex = planeindex;
4783 bestplanescore = planescore;
4787 planeindex = bestplaneindex;
4789 // if this surface does not fit any known plane rendered this frame, add one
4790 if (planeindex < 0 || bestplanescore > 0.001f)
4792 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4794 // store the new plane
4795 planeindex = r_fb.water.numwaterplanes++;
4796 p = r_fb.water.waterplanes + planeindex;
4798 // clear materialflags and pvs
4799 p->materialflags = 0;
4800 p->pvsvalid = false;
4801 p->camera_entity = t->camera_entity;
4802 VectorCopy(mins, p->mins);
4803 VectorCopy(maxs, p->maxs);
4807 // We're totally screwed.
4813 // merge mins/maxs when we're adding this surface to the plane
4814 p = r_fb.water.waterplanes + planeindex;
4815 p->mins[0] = min(p->mins[0], mins[0]);
4816 p->mins[1] = min(p->mins[1], mins[1]);
4817 p->mins[2] = min(p->mins[2], mins[2]);
4818 p->maxs[0] = max(p->maxs[0], maxs[0]);
4819 p->maxs[1] = max(p->maxs[1], maxs[1]);
4820 p->maxs[2] = max(p->maxs[2], maxs[2]);
4822 // merge this surface's materialflags into the waterplane
4823 p->materialflags |= t->currentmaterialflags;
4824 if(!(p->materialflags & MATERIALFLAG_CAMERA))
4826 // merge this surface's PVS into the waterplane
4827 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4828 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4830 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4836 extern cvar_t r_drawparticles;
4837 extern cvar_t r_drawdecals;
4839 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4842 r_refdef_view_t originalview;
4843 r_refdef_view_t myview;
4844 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;
4845 r_waterstate_waterplane_t *p;
4847 r_rendertarget_t *rt;
4849 originalview = r_refdef.view;
4851 // lowquality hack, temporarily shut down some cvars and restore afterwards
4852 qualityreduction = r_water_lowquality.integer;
4853 if (qualityreduction > 0)
4855 if (qualityreduction >= 1)
4857 old_r_shadows = r_shadows.integer;
4858 old_r_worldrtlight = r_shadow_realtime_world.integer;
4859 old_r_dlight = r_shadow_realtime_dlight.integer;
4860 Cvar_SetValueQuick(&r_shadows, 0);
4861 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4862 Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4864 if (qualityreduction >= 2)
4866 old_r_dynamic = r_dynamic.integer;
4867 old_r_particles = r_drawparticles.integer;
4868 old_r_decals = r_drawdecals.integer;
4869 Cvar_SetValueQuick(&r_dynamic, 0);
4870 Cvar_SetValueQuick(&r_drawparticles, 0);
4871 Cvar_SetValueQuick(&r_drawdecals, 0);
4875 for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4877 p->rt_reflection = NULL;
4878 p->rt_refraction = NULL;
4879 p->rt_camera = NULL;
4883 r_refdef.view = originalview;
4884 r_refdef.view.showdebug = false;
4885 r_refdef.view.width = r_fb.water.waterwidth;
4886 r_refdef.view.height = r_fb.water.waterheight;
4887 r_refdef.view.useclipplane = true;
4888 myview = r_refdef.view;
4889 r_fb.water.renderingscene = true;
4890 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4892 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4895 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4897 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);
4898 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4900 r_refdef.view = myview;
4901 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4902 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4903 if(r_water_scissormode.integer)
4905 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4906 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4908 p->rt_reflection = NULL;
4909 p->rt_refraction = NULL;
4910 p->rt_camera = NULL;
4915 r_refdef.view.clipplane = p->plane;
4916 // reflected view origin may be in solid, so don't cull with it
4917 r_refdef.view.usevieworiginculling = false;
4918 // reverse the cullface settings for this render
4919 r_refdef.view.cullface_front = GL_FRONT;
4920 r_refdef.view.cullface_back = GL_BACK;
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 >= 2) && !chase_active.integer);
4932 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4933 GL_ScissorTest(false);
4934 R_ClearScreen(r_refdef.fogenabled);
4935 GL_ScissorTest(true);
4936 if(r_water_scissormode.integer & 2)
4937 R_View_UpdateWithScissor(myscissor);
4940 R_AnimCache_CacheVisibleEntities();
4941 if(r_water_scissormode.integer & 1)
4942 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4943 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4945 r_fb.water.hideplayer = false;
4946 p->rt_reflection = rt;
4949 // render the normal view scene and copy into texture
4950 // (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)
4951 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4953 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);
4954 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4956 r_refdef.view = myview;
4957 if(r_water_scissormode.integer)
4959 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4960 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4962 p->rt_reflection = NULL;
4963 p->rt_refraction = NULL;
4964 p->rt_camera = NULL;
4969 // combined pvs (based on what can be seen from each surface center)
4970 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4972 r_refdef.view.usecustompvs = true;
4974 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4976 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4979 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4981 r_refdef.view.clipplane = p->plane;
4982 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4983 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4985 if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4987 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4988 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4989 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4990 R_RenderView_UpdateViewVectors();
4991 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4993 r_refdef.view.usecustompvs = true;
4994 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);
4998 PlaneClassify(&r_refdef.view.clipplane);
5000 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5001 GL_ScissorTest(false);
5002 R_ClearScreen(r_refdef.fogenabled);
5003 GL_ScissorTest(true);
5004 if(r_water_scissormode.integer & 2)
5005 R_View_UpdateWithScissor(myscissor);
5008 R_AnimCache_CacheVisibleEntities();
5009 if(r_water_scissormode.integer & 1)
5010 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5011 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5013 r_fb.water.hideplayer = false;
5014 p->rt_refraction = rt;
5016 else if (p->materialflags & MATERIALFLAG_CAMERA)
5018 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);
5019 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5021 r_refdef.view = myview;
5023 r_refdef.view.clipplane = p->plane;
5024 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5025 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5027 r_refdef.view.width = r_fb.water.camerawidth;
5028 r_refdef.view.height = r_fb.water.cameraheight;
5029 r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5030 r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5031 r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5032 r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5034 if(p->camera_entity)
5036 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5037 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5040 // note: all of the view is used for displaying... so
5041 // there is no use in scissoring
5043 // reverse the cullface settings for this render
5044 r_refdef.view.cullface_front = GL_FRONT;
5045 r_refdef.view.cullface_back = GL_BACK;
5046 // also reverse the view matrix
5047 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
5048 R_RenderView_UpdateViewVectors();
5049 if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5051 r_refdef.view.usecustompvs = true;
5052 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);
5055 // camera needs no clipplane
5056 r_refdef.view.useclipplane = false;
5057 // TODO: is the camera origin always valid? if so we don't need to clear this
5058 r_refdef.view.usevieworiginculling = false;
5060 PlaneClassify(&r_refdef.view.clipplane);
5062 r_fb.water.hideplayer = false;
5064 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5065 GL_ScissorTest(false);
5066 R_ClearScreen(r_refdef.fogenabled);
5067 GL_ScissorTest(true);
5069 R_AnimCache_CacheVisibleEntities();
5070 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5072 r_fb.water.hideplayer = false;
5077 r_fb.water.renderingscene = false;
5078 r_refdef.view = originalview;
5079 R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5081 R_AnimCache_CacheVisibleEntities();
5084 r_refdef.view = originalview;
5085 r_fb.water.renderingscene = false;
5086 Cvar_SetValueQuick(&r_water, 0);
5087 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
5089 // lowquality hack, restore cvars
5090 if (qualityreduction > 0)
5092 if (qualityreduction >= 1)
5094 Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5095 Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5096 Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5098 if (qualityreduction >= 2)
5100 Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5101 Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5102 Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5107 static void R_Bloom_StartFrame(void)
5109 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5110 int viewwidth, viewheight;
5111 textype_t textype = TEXTYPE_COLORBUFFER;
5113 // clear the pointers to rendertargets from last frame as they're stale
5114 r_fb.rt_screen = NULL;
5115 r_fb.rt_bloom = NULL;
5117 switch (vid.renderpath)
5119 case RENDERPATH_GL32:
5120 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5121 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5122 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5124 case RENDERPATH_GLES2:
5125 r_fb.usedepthtextures = false;
5129 if (r_viewscale_fpsscaling.integer)
5131 double actualframetime;
5132 double targetframetime;
5134 actualframetime = r_refdef.lastdrawscreentime;
5135 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5136 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5137 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5138 if (r_viewscale_fpsscaling_stepsize.value > 0)
5139 adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5140 viewscalefpsadjusted += adjust;
5141 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5144 viewscalefpsadjusted = 1.0f;
5146 R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5148 // set bloomwidth and bloomheight to the bloom resolution that will be
5149 // used (often less than the screen resolution for faster rendering)
5150 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5151 r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5152 r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5153 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5154 r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5156 // calculate desired texture sizes
5157 screentexturewidth = viewwidth;
5158 screentextureheight = viewheight;
5159 bloomtexturewidth = r_fb.bloomwidth;
5160 bloomtextureheight = r_fb.bloomheight;
5162 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))
5164 Cvar_SetValueQuick(&r_bloom, 0);
5165 Cvar_SetValueQuick(&r_motionblur, 0);
5166 Cvar_SetValueQuick(&r_damageblur, 0);
5169 // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5170 if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5172 if (r_fb.ghosttexture)
5173 R_FreeTexture(r_fb.ghosttexture);
5174 r_fb.ghosttexture = NULL;
5176 r_fb.screentexturewidth = screentexturewidth;
5177 r_fb.screentextureheight = screentextureheight;
5178 r_fb.textype = textype;
5180 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5182 if (r_motionblur.value > 0 || r_damageblur.value > 0)
5183 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);
5184 r_fb.ghosttexture_valid = false;
5188 if (r_bloom.integer)
5190 // bloom texture is a different resolution
5191 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5192 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5193 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5196 r_fb.bloomwidth = r_fb.bloomheight = 0;
5198 r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5200 r_refdef.view.clear = true;
5203 static void R_Bloom_MakeTexture(void)
5206 float xoffset, yoffset, r, brighten;
5207 float colorscale = r_bloom_colorscale.value;
5208 r_viewport_t bloomviewport;
5209 r_rendertarget_t *prev, *cur;
5210 textype_t textype = r_fb.rt_screen->colortextype[0];
5212 r_refdef.stats[r_stat_bloom]++;
5214 R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5216 // scale down screen texture to the bloom texture size
5218 prev = r_fb.rt_screen;
5219 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5220 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5221 R_SetViewport(&bloomviewport);
5222 GL_CullFace(GL_NONE);
5223 GL_DepthTest(false);
5224 GL_BlendFunc(GL_ONE, GL_ZERO);
5225 GL_Color(colorscale, colorscale, colorscale, 1);
5226 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5227 // TODO: do boxfilter scale-down in shader?
5228 R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5229 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5230 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5231 // we now have a properly scaled bloom image
5233 // multiply bloom image by itself as many times as desired to darken it
5234 // TODO: if people actually use this it could be done more quickly in the previous shader pass
5235 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5238 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5239 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5241 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5243 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5244 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5245 GL_Color(1,1,1,1); // no fix factor supported here
5246 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5247 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5248 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5249 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5253 range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5254 brighten = r_bloom_brighten.value;
5255 brighten = sqrt(brighten);
5257 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5259 for (dir = 0;dir < 2;dir++)
5262 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5263 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5264 // blend on at multiple vertical offsets to achieve a vertical blur
5265 // TODO: do offset blends using GLSL
5266 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5268 GL_BlendFunc(GL_ONE, GL_ZERO);
5270 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5272 for (x = -range;x <= range;x++)
5274 if (!dir){xoffset = 0;yoffset = x;}
5275 else {xoffset = x;yoffset = 0;}
5276 xoffset /= (float)prev->texturewidth;
5277 yoffset /= (float)prev->textureheight;
5278 // compute a texcoord array with the specified x and y offset
5279 r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5280 r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5281 r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5282 r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5283 r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5284 r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5285 r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5286 r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5287 // this r value looks like a 'dot' particle, fading sharply to
5288 // black at the edges
5289 // (probably not realistic but looks good enough)
5290 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5291 //r = brighten/(range*2+1);
5292 r = brighten / (range * 2 + 1);
5294 r *= (1 - x*x/(float)((range+1)*(range+1)));
5298 GL_Color(r, r, r, 1);
5300 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5302 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5303 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5305 GL_BlendFunc(GL_ONE, GL_ONE);
5310 // now we have the bloom image, so keep track of it
5311 r_fb.rt_bloom = cur;
5314 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5316 dpuint64 permutation;
5317 float uservecs[4][4];
5318 rtexture_t *viewtexture;
5319 rtexture_t *bloomtexture;
5321 R_EntityMatrix(&identitymatrix);
5323 if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5325 // declare variables
5326 float blur_factor, blur_mouseaccel, blur_velocity;
5327 static float blur_average;
5328 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5330 // set a goal for the factoring
5331 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5332 / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5333 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5334 / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5335 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5336 + (blur_mouseaccel * r_motionblur_mousefactor.value));
5338 // from the goal, pick an averaged value between goal and last value
5339 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5340 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5342 // enforce minimum amount of blur
5343 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5345 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5347 // calculate values into a standard alpha
5348 cl.motionbluralpha = 1 - exp(-
5350 (r_motionblur.value * blur_factor / 80)
5352 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5355 max(0.0001, cl.time - cl.oldtime) // fps independent
5358 // randomization for the blur value to combat persistent ghosting
5359 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5360 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5363 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5364 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5366 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5367 GL_Color(1, 1, 1, cl.motionbluralpha);
5368 R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5369 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5370 R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5371 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5372 r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5375 // updates old view angles for next pass
5376 VectorCopy(cl.viewangles, blur_oldangles);
5378 // copy view into the ghost texture
5379 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5380 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5381 r_fb.ghosttexture_valid = true;
5384 if (r_fb.bloomwidth)
5386 // make the bloom texture
5387 R_Bloom_MakeTexture();
5390 #if _MSC_VER >= 1400
5391 #define sscanf sscanf_s
5393 memset(uservecs, 0, sizeof(uservecs));
5394 if (r_glsl_postprocess_uservec1_enable.integer)
5395 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5396 if (r_glsl_postprocess_uservec2_enable.integer)
5397 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5398 if (r_glsl_postprocess_uservec3_enable.integer)
5399 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5400 if (r_glsl_postprocess_uservec4_enable.integer)
5401 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5403 // render to the screen fbo
5404 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5405 GL_Color(1, 1, 1, 1);
5406 GL_BlendFunc(GL_ONE, GL_ZERO);
5408 viewtexture = r_fb.rt_screen->colortexture[0];
5409 bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5411 if (r_rendertarget_debug.integer >= 0)
5413 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5414 if (rt && rt->colortexture[0])
5416 viewtexture = rt->colortexture[0];
5417 bloomtexture = NULL;
5421 R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5422 switch(vid.renderpath)
5424 case RENDERPATH_GL32:
5425 case RENDERPATH_GLES2:
5427 (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5428 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5429 | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5430 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5431 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5432 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5433 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , viewtexture);
5434 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , bloomtexture);
5435 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps );
5436 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]);
5437 if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5438 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]);
5439 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]);
5440 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]);
5441 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]);
5442 if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value);
5443 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5444 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);
5447 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5448 r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5451 matrix4x4_t r_waterscrollmatrix;
5453 void R_UpdateFog(void)
5456 if (gamemode == GAME_NEHAHRA)
5458 if (gl_fogenable.integer)
5460 r_refdef.oldgl_fogenable = true;
5461 r_refdef.fog_density = gl_fogdensity.value;
5462 r_refdef.fog_red = gl_fogred.value;
5463 r_refdef.fog_green = gl_foggreen.value;
5464 r_refdef.fog_blue = gl_fogblue.value;
5465 r_refdef.fog_alpha = 1;
5466 r_refdef.fog_start = 0;
5467 r_refdef.fog_end = gl_skyclip.value;
5468 r_refdef.fog_height = 1<<30;
5469 r_refdef.fog_fadedepth = 128;
5471 else if (r_refdef.oldgl_fogenable)
5473 r_refdef.oldgl_fogenable = false;
5474 r_refdef.fog_density = 0;
5475 r_refdef.fog_red = 0;
5476 r_refdef.fog_green = 0;
5477 r_refdef.fog_blue = 0;
5478 r_refdef.fog_alpha = 0;
5479 r_refdef.fog_start = 0;
5480 r_refdef.fog_end = 0;
5481 r_refdef.fog_height = 1<<30;
5482 r_refdef.fog_fadedepth = 128;
5487 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5488 r_refdef.fog_start = max(0, r_refdef.fog_start);
5489 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5491 if (r_refdef.fog_density && r_drawfog.integer)
5493 r_refdef.fogenabled = true;
5494 // this is the point where the fog reaches 0.9986 alpha, which we
5495 // consider a good enough cutoff point for the texture
5496 // (0.9986 * 256 == 255.6)
5497 if (r_fog_exp2.integer)
5498 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5500 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5501 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5502 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5503 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5504 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5505 R_BuildFogHeightTexture();
5506 // fog color was already set
5507 // update the fog texture
5508 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)
5509 R_BuildFogTexture();
5510 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5511 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5514 r_refdef.fogenabled = false;
5517 if (r_refdef.fog_density)
5519 r_refdef.fogcolor[0] = r_refdef.fog_red;
5520 r_refdef.fogcolor[1] = r_refdef.fog_green;
5521 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5523 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5524 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5525 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5526 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5530 VectorCopy(r_refdef.fogcolor, fogvec);
5531 // color.rgb *= ContrastBoost * SceneBrightness;
5532 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5533 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5534 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5535 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5540 void R_UpdateVariables(void)
5544 r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5546 r_refdef.farclip = r_farclip_base.value;
5547 if (r_refdef.scene.worldmodel)
5548 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5549 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5551 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5552 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5553 r_refdef.polygonfactor = 0;
5554 r_refdef.polygonoffset = 0;
5556 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5557 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5558 r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5559 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5560 r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5561 if (FAKELIGHT_ENABLED)
5563 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5565 else if (r_refdef.scene.worldmodel)
5567 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5569 if (r_showsurfaces.integer)
5571 r_refdef.scene.rtworld = false;
5572 r_refdef.scene.rtworldshadows = false;
5573 r_refdef.scene.rtdlight = false;
5574 r_refdef.scene.rtdlightshadows = false;
5575 r_refdef.scene.lightmapintensity = 0;
5578 r_gpuskeletal = false;
5579 switch(vid.renderpath)
5581 case RENDERPATH_GL32:
5582 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5583 case RENDERPATH_GLES2:
5584 if(!vid_gammatables_trivial)
5586 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5588 // build GLSL gamma texture
5589 #define RAMPWIDTH 256
5590 unsigned short ramp[RAMPWIDTH * 3];
5591 unsigned char rampbgr[RAMPWIDTH][4];
5594 r_texture_gammaramps_serial = vid_gammatables_serial;
5596 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5597 for(i = 0; i < RAMPWIDTH; ++i)
5599 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5600 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5601 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5604 if (r_texture_gammaramps)
5606 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5610 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5616 // remove GLSL gamma texture
5622 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5623 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5629 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5630 if( scenetype != r_currentscenetype ) {
5631 // store the old scenetype
5632 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5633 r_currentscenetype = scenetype;
5634 // move in the new scene
5635 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5644 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5646 // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5647 if( scenetype == r_currentscenetype ) {
5648 return &r_refdef.scene;
5650 return &r_scenes_store[ scenetype ];
5654 static int R_SortEntities_Compare(const void *ap, const void *bp)
5656 const entity_render_t *a = *(const entity_render_t **)ap;
5657 const entity_render_t *b = *(const entity_render_t **)bp;
5660 if(a->model < b->model)
5662 if(a->model > b->model)
5666 // TODO possibly calculate the REAL skinnum here first using
5668 if(a->skinnum < b->skinnum)
5670 if(a->skinnum > b->skinnum)
5673 // everything we compared is equal
5676 static void R_SortEntities(void)
5678 // below or equal 2 ents, sorting never gains anything
5679 if(r_refdef.scene.numentities <= 2)
5682 qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5690 extern cvar_t r_shadow_bouncegrid;
5691 extern cvar_t v_isometric;
5692 extern void V_MakeViewIsometric(void);
5693 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5695 matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5697 rtexture_t *viewdepthtexture = NULL;
5698 rtexture_t *viewcolortexture = NULL;
5699 int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5701 // finish any 2D rendering that was queued
5704 if (r_timereport_active)
5705 R_TimeReport("start");
5706 r_textureframe++; // used only by R_GetCurrentTexture
5707 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5709 if(R_CompileShader_CheckStaticParms())
5712 if (!r_drawentities.integer)
5713 r_refdef.scene.numentities = 0;
5714 else if (r_sortentities.integer)
5717 R_AnimCache_ClearCache();
5719 /* adjust for stereo display */
5720 if(R_Stereo_Active())
5722 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);
5723 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5726 if (r_refdef.view.isoverlay)
5728 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5729 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5730 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5731 R_TimeReport("depthclear");
5733 r_refdef.view.showdebug = false;
5735 r_fb.water.enabled = false;
5736 r_fb.water.numwaterplanes = 0;
5738 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5740 r_refdef.view.matrix = originalmatrix;
5746 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5748 r_refdef.view.matrix = originalmatrix;
5752 r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5753 if (v_isometric.integer && r_refdef.view.ismain)
5754 V_MakeViewIsometric();
5756 r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5758 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5759 // in sRGB fallback, behave similar to true sRGB: convert this
5760 // value from linear to sRGB
5761 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5763 R_RenderView_UpdateViewVectors();
5765 R_Shadow_UpdateWorldLightSelection();
5767 // this will set up r_fb.rt_screen
5768 R_Bloom_StartFrame();
5770 // apply bloom brightness offset
5772 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5774 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5777 viewfbo = r_fb.rt_screen->fbo;
5778 viewdepthtexture = r_fb.rt_screen->depthtexture;
5779 viewcolortexture = r_fb.rt_screen->colortexture[0];
5783 viewheight = height;
5786 R_Water_StartFrame();
5789 if (r_timereport_active)
5790 R_TimeReport("viewsetup");
5792 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5794 // clear the whole fbo every frame - otherwise the driver will consider
5795 // it to be an inter-frame texture and stall in multi-gpu configurations
5797 GL_ScissorTest(false);
5798 R_ClearScreen(r_refdef.fogenabled);
5799 if (r_timereport_active)
5800 R_TimeReport("viewclear");
5802 r_refdef.view.clear = true;
5804 r_refdef.view.showdebug = true;
5807 if (r_timereport_active)
5808 R_TimeReport("visibility");
5810 R_AnimCache_CacheVisibleEntities();
5811 if (r_timereport_active)
5812 R_TimeReport("animcache");
5814 R_Shadow_UpdateBounceGridTexture();
5815 if (r_timereport_active && r_shadow_bouncegrid.integer)
5816 R_TimeReport("bouncegrid");
5818 r_fb.water.numwaterplanes = 0;
5819 if (r_fb.water.enabled)
5820 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5822 // for the actual view render we use scissoring a fair amount, so scissor
5823 // test needs to be on
5825 GL_ScissorTest(true);
5826 GL_Scissor(viewx, viewy, viewwidth, viewheight);
5827 R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5828 r_fb.water.numwaterplanes = 0;
5830 // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5831 GL_ScissorTest(false);
5833 R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5834 if (r_timereport_active)
5835 R_TimeReport("blendview");
5837 r_refdef.view.matrix = originalmatrix;
5841 // go back to 2d rendering
5845 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5847 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5849 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5850 if (r_timereport_active)
5851 R_TimeReport("waterworld");
5854 // don't let sound skip if going slow
5855 if (r_refdef.scene.extraupdate)
5858 R_DrawModelsAddWaterPlanes();
5859 if (r_timereport_active)
5860 R_TimeReport("watermodels");
5862 if (r_fb.water.numwaterplanes)
5864 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5865 if (r_timereport_active)
5866 R_TimeReport("waterscenes");
5870 extern cvar_t cl_locs_show;
5871 static void R_DrawLocs(void);
5872 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5873 static void R_DrawModelDecals(void);
5874 extern cvar_t cl_decals_newsystem;
5875 extern qboolean r_shadow_usingdeferredprepass;
5876 extern int r_shadow_shadowmapatlas_modelshadows_size;
5877 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5879 qboolean shadowmapping = false;
5881 if (r_timereport_active)
5882 R_TimeReport("beginscene");
5884 r_refdef.stats[r_stat_renders]++;
5888 // don't let sound skip if going slow
5889 if (r_refdef.scene.extraupdate)
5892 R_MeshQueue_BeginScene();
5896 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);
5898 if (r_timereport_active)
5899 R_TimeReport("skystartframe");
5901 if (cl.csqc_vidvars.drawworld)
5903 // don't let sound skip if going slow
5904 if (r_refdef.scene.extraupdate)
5907 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5909 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5910 if (r_timereport_active)
5911 R_TimeReport("worldsky");
5914 if (R_DrawBrushModelsSky() && r_timereport_active)
5915 R_TimeReport("bmodelsky");
5917 if (skyrendermasked && skyrenderlater)
5919 // we have to force off the water clipping plane while rendering sky
5920 R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5922 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5923 if (r_timereport_active)
5924 R_TimeReport("sky");
5928 // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5929 r_shadow_viewfbo = viewfbo;
5930 r_shadow_viewdepthtexture = viewdepthtexture;
5931 r_shadow_viewcolortexture = viewcolortexture;
5932 r_shadow_viewx = viewx;
5933 r_shadow_viewy = viewy;
5934 r_shadow_viewwidth = viewwidth;
5935 r_shadow_viewheight = viewheight;
5937 R_Shadow_PrepareModelShadows();
5938 R_Shadow_PrepareLights();
5939 if (r_timereport_active)
5940 R_TimeReport("preparelights");
5942 // render all the shadowmaps that will be used for this view
5943 shadowmapping = R_Shadow_ShadowMappingEnabled();
5944 if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5946 R_Shadow_DrawShadowMaps();
5947 if (r_timereport_active)
5948 R_TimeReport("shadowmaps");
5951 // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5952 if (r_shadow_usingdeferredprepass)
5953 R_Shadow_DrawPrepass();
5955 // now we begin the forward pass of the view render
5956 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5958 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5959 if (r_timereport_active)
5960 R_TimeReport("worlddepth");
5962 if (r_depthfirst.integer >= 2)
5964 R_DrawModelsDepth();
5965 if (r_timereport_active)
5966 R_TimeReport("modeldepth");
5969 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5971 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5972 if (r_timereport_active)
5973 R_TimeReport("world");
5976 // don't let sound skip if going slow
5977 if (r_refdef.scene.extraupdate)
5981 if (r_timereport_active)
5982 R_TimeReport("models");
5984 // don't let sound skip if going slow
5985 if (r_refdef.scene.extraupdate)
5988 if (!r_shadow_usingdeferredprepass)
5990 R_Shadow_DrawLights();
5991 if (r_timereport_active)
5992 R_TimeReport("rtlights");
5995 // don't let sound skip if going slow
5996 if (r_refdef.scene.extraupdate)
5999 if (cl.csqc_vidvars.drawworld)
6001 if (cl_decals_newsystem.integer)
6003 R_DrawModelDecals();
6004 if (r_timereport_active)
6005 R_TimeReport("modeldecals");
6010 if (r_timereport_active)
6011 R_TimeReport("decals");
6015 if (r_timereport_active)
6016 R_TimeReport("particles");
6019 if (r_timereport_active)
6020 R_TimeReport("explosions");
6023 if (r_refdef.view.showdebug)
6025 if (cl_locs_show.integer)
6028 if (r_timereport_active)
6029 R_TimeReport("showlocs");
6032 if (r_drawportals.integer)
6035 if (r_timereport_active)
6036 R_TimeReport("portals");
6039 if (r_showbboxes_client.value > 0)
6041 R_DrawEntityBBoxes(CLVM_prog);
6042 if (r_timereport_active)
6043 R_TimeReport("clbboxes");
6045 if (r_showbboxes.value > 0)
6047 R_DrawEntityBBoxes(SVVM_prog);
6048 if (r_timereport_active)
6049 R_TimeReport("svbboxes");
6053 if (r_transparent.integer)
6055 R_MeshQueue_RenderTransparent();
6056 if (r_timereport_active)
6057 R_TimeReport("drawtrans");
6060 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))
6062 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6063 if (r_timereport_active)
6064 R_TimeReport("worlddebug");
6065 R_DrawModelsDebug();
6066 if (r_timereport_active)
6067 R_TimeReport("modeldebug");
6070 if (cl.csqc_vidvars.drawworld)
6072 R_Shadow_DrawCoronas();
6073 if (r_timereport_active)
6074 R_TimeReport("coronas");
6077 // don't let sound skip if going slow
6078 if (r_refdef.scene.extraupdate)
6082 static const unsigned short bboxelements[36] =
6092 #define BBOXEDGES 13
6093 static const float bboxedges[BBOXEDGES][6] =
6096 { 0, 0, 0, 1, 1, 1 },
6098 { 0, 0, 0, 0, 1, 0 },
6099 { 0, 0, 0, 1, 0, 0 },
6100 { 0, 1, 0, 1, 1, 0 },
6101 { 1, 0, 0, 1, 1, 0 },
6103 { 0, 0, 1, 0, 1, 1 },
6104 { 0, 0, 1, 1, 0, 1 },
6105 { 0, 1, 1, 1, 1, 1 },
6106 { 1, 0, 1, 1, 1, 1 },
6108 { 0, 0, 0, 0, 0, 1 },
6109 { 1, 0, 0, 1, 0, 1 },
6110 { 0, 1, 0, 0, 1, 1 },
6111 { 1, 1, 0, 1, 1, 1 },
6114 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6116 int numvertices = BBOXEDGES * 8;
6117 float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6118 int numtriangles = BBOXEDGES * 12;
6119 unsigned short elements[BBOXEDGES * 36];
6121 float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6123 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6125 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6126 GL_DepthMask(false);
6127 GL_DepthRange(0, 1);
6128 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6130 for (edge = 0; edge < BBOXEDGES; edge++)
6132 for (i = 0; i < 3; i++)
6134 edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6135 edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6137 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6138 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6139 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6140 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6141 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6142 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6143 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6144 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6145 for (i = 0; i < 36; i++)
6146 elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6148 R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6149 if (r_refdef.fogenabled)
6151 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6153 f1 = RSurf_FogVertex(v);
6155 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6156 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6157 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6160 R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6161 R_Mesh_ResetTextureState();
6162 R_SetupShader_Generic_NoTexture(false, false);
6163 R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6166 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6168 // hacky overloading of the parameters
6169 prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6172 prvm_edict_t *edict;
6174 GL_CullFace(GL_NONE);
6175 R_SetupShader_Generic_NoTexture(false, false);
6177 for (i = 0;i < numsurfaces;i++)
6179 edict = PRVM_EDICT_NUM(surfacelist[i]);
6180 switch ((int)PRVM_serveredictfloat(edict, solid))
6182 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
6183 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
6184 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
6185 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6186 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
6187 case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break;
6188 default: Vector4Set(color, 0, 0, 0, 0.50);break;
6190 if (prog == CLVM_prog)
6191 color[3] *= r_showbboxes_client.value;
6193 color[3] *= r_showbboxes.value;
6194 color[3] = bound(0, color[3], 1);
6195 GL_DepthTest(!r_showdisabledepthtest.integer);
6196 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6200 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6203 prvm_edict_t *edict;
6209 for (i = 0; i < prog->num_edicts; i++)
6211 edict = PRVM_EDICT_NUM(i);
6212 if (edict->priv.server->free)
6214 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6215 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6217 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6219 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6220 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6224 static const int nomodelelement3i[24] =
6236 static const unsigned short nomodelelement3s[24] =
6248 static const float nomodelvertex3f[6*3] =
6258 static const float nomodelcolor4f[6*4] =
6260 0.0f, 0.0f, 0.5f, 1.0f,
6261 0.0f, 0.0f, 0.5f, 1.0f,
6262 0.0f, 0.5f, 0.0f, 1.0f,
6263 0.0f, 0.5f, 0.0f, 1.0f,
6264 0.5f, 0.0f, 0.0f, 1.0f,
6265 0.5f, 0.0f, 0.0f, 1.0f
6268 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6274 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);
6276 // this is only called once per entity so numsurfaces is always 1, and
6277 // surfacelist is always {0}, so this code does not handle batches
6279 if (rsurface.ent_flags & RENDER_ADDITIVE)
6281 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6282 GL_DepthMask(false);
6284 else if (ent->alpha < 1)
6286 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6287 GL_DepthMask(false);
6291 GL_BlendFunc(GL_ONE, GL_ZERO);
6294 GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6295 GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6296 GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6297 GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6298 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6299 for (i = 0, c = color4f;i < 6;i++, c += 4)
6301 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6302 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6303 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6306 if (r_refdef.fogenabled)
6308 for (i = 0, c = color4f;i < 6;i++, c += 4)
6310 f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6312 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6313 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6314 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6317 // R_Mesh_ResetTextureState();
6318 R_SetupShader_Generic_NoTexture(false, false);
6319 R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6320 R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6323 void R_DrawNoModel(entity_render_t *ent)
6326 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6327 if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6328 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6330 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6333 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6335 vec3_t right1, right2, diff, normal;
6337 VectorSubtract (org2, org1, normal);
6339 // calculate 'right' vector for start
6340 VectorSubtract (r_refdef.view.origin, org1, diff);
6341 CrossProduct (normal, diff, right1);
6342 VectorNormalize (right1);
6344 // calculate 'right' vector for end
6345 VectorSubtract (r_refdef.view.origin, org2, diff);
6346 CrossProduct (normal, diff, right2);
6347 VectorNormalize (right2);
6349 vert[ 0] = org1[0] + width * right1[0];
6350 vert[ 1] = org1[1] + width * right1[1];
6351 vert[ 2] = org1[2] + width * right1[2];
6352 vert[ 3] = org1[0] - width * right1[0];
6353 vert[ 4] = org1[1] - width * right1[1];
6354 vert[ 5] = org1[2] - width * right1[2];
6355 vert[ 6] = org2[0] - width * right2[0];
6356 vert[ 7] = org2[1] - width * right2[1];
6357 vert[ 8] = org2[2] - width * right2[2];
6358 vert[ 9] = org2[0] + width * right2[0];
6359 vert[10] = org2[1] + width * right2[1];
6360 vert[11] = org2[2] + width * right2[2];
6363 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)
6365 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6366 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6367 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6368 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6369 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6370 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6371 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6372 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6373 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6374 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6375 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6376 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6379 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6384 VectorSet(v, x, y, z);
6385 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6386 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6388 if (i == mesh->numvertices)
6390 if (mesh->numvertices < mesh->maxvertices)
6392 VectorCopy(v, vertex3f);
6393 mesh->numvertices++;
6395 return mesh->numvertices;
6401 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6405 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6406 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6407 e = mesh->element3i + mesh->numtriangles * 3;
6408 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6410 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6411 if (mesh->numtriangles < mesh->maxtriangles)
6416 mesh->numtriangles++;
6418 element[1] = element[2];
6422 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6426 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6427 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6428 e = mesh->element3i + mesh->numtriangles * 3;
6429 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6431 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6432 if (mesh->numtriangles < mesh->maxtriangles)
6437 mesh->numtriangles++;
6439 element[1] = element[2];
6443 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6444 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6446 int planenum, planenum2;
6449 mplane_t *plane, *plane2;
6451 double temppoints[2][256*3];
6452 // figure out how large a bounding box we need to properly compute this brush
6454 for (w = 0;w < numplanes;w++)
6455 maxdist = max(maxdist, fabs(planes[w].dist));
6456 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6457 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6458 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6462 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6463 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6465 if (planenum2 == planenum)
6467 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);
6470 if (tempnumpoints < 3)
6472 // generate elements forming a triangle fan for this polygon
6473 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6477 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)
6479 texturelayer_t *layer;
6480 layer = t->currentlayers + t->currentnumlayers++;
6482 layer->depthmask = depthmask;
6483 layer->blendfunc1 = blendfunc1;
6484 layer->blendfunc2 = blendfunc2;
6485 layer->texture = texture;
6486 layer->texmatrix = *matrix;
6487 layer->color[0] = r;
6488 layer->color[1] = g;
6489 layer->color[2] = b;
6490 layer->color[3] = a;
6493 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6495 if(parms[0] == 0 && parms[1] == 0)
6497 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6498 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6503 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6506 index = parms[2] + rsurface.shadertime * parms[3];
6507 index -= floor(index);
6508 switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6511 case Q3WAVEFUNC_NONE:
6512 case Q3WAVEFUNC_NOISE:
6513 case Q3WAVEFUNC_COUNT:
6516 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6517 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6518 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6519 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6520 case Q3WAVEFUNC_TRIANGLE:
6522 f = index - floor(index);
6535 f = parms[0] + parms[1] * f;
6536 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6537 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6541 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6548 matrix4x4_t matrix, temp;
6549 // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6550 // it's better to have one huge fixup every 9 hours than gradual
6551 // degradation over time which looks consistently bad after many hours.
6553 // tcmod scroll in particular suffers from this degradation which can't be
6554 // effectively worked around even with floor() tricks because we don't
6555 // know if tcmod scroll is the last tcmod being applied, and for clampmap
6556 // a workaround involving floor() would be incorrect anyway...
6557 shadertime = rsurface.shadertime;
6558 if (shadertime >= 32768.0f)
6559 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6560 switch(tcmod->tcmod)
6564 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6565 matrix = r_waterscrollmatrix;
6567 matrix = identitymatrix;
6569 case Q3TCMOD_ENTITYTRANSLATE:
6570 // this is used in Q3 to allow the gamecode to control texcoord
6571 // scrolling on the entity, which is not supported in darkplaces yet.
6572 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6574 case Q3TCMOD_ROTATE:
6575 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6576 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6577 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6580 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6582 case Q3TCMOD_SCROLL:
6583 // this particular tcmod is a "bug for bug" compatible one with regards to
6584 // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6585 // specifically did the wrapping and so we must mimic that...
6586 offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6587 offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6588 Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6590 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6591 w = (int) tcmod->parms[0];
6592 h = (int) tcmod->parms[1];
6593 f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6595 idx = (int) floor(f * w * h);
6596 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6598 case Q3TCMOD_STRETCH:
6599 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6600 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6602 case Q3TCMOD_TRANSFORM:
6603 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
6604 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
6605 VectorSet(tcmat + 6, 0 , 0 , 1);
6606 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
6607 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6609 case Q3TCMOD_TURBULENT:
6610 // this is handled in the RSurf_PrepareVertices function
6611 matrix = identitymatrix;
6615 Matrix4x4_Concat(texmatrix, &matrix, &temp);
6618 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6620 int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6621 char name[MAX_QPATH];
6622 skinframe_t *skinframe;
6623 unsigned char pixels[296*194];
6624 strlcpy(cache->name, skinname, sizeof(cache->name));
6625 dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6626 if (developer_loading.integer)
6627 Con_Printf("loading %s\n", name);
6628 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6629 if (!skinframe || !skinframe->base)
6632 fs_offset_t filesize;
6634 f = FS_LoadFile(name, tempmempool, true, &filesize);
6637 if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6638 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6642 cache->skinframe = skinframe;
6645 texture_t *R_GetCurrentTexture(texture_t *t)
6648 const entity_render_t *ent = rsurface.entity;
6649 dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6650 q3shaderinfo_layer_tcmod_t *tcmod;
6651 float specularscale = 0.0f;
6653 if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6654 return t->currentframe;
6655 t->update_lastrenderframe = r_textureframe;
6656 t->update_lastrenderentity = (void *)ent;
6658 if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6659 t->camera_entity = ent->entitynumber;
6661 t->camera_entity = 0;
6663 // switch to an alternate material if this is a q1bsp animated material
6665 texture_t *texture = t;
6666 int s = rsurface.ent_skinnum;
6667 if ((unsigned int)s >= (unsigned int)model->numskins)
6669 if (model->skinscenes)
6671 if (model->skinscenes[s].framecount > 1)
6672 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6674 s = model->skinscenes[s].firstframe;
6677 t = t + s * model->num_surfaces;
6680 // use an alternate animation if the entity's frame is not 0,
6681 // and only if the texture has an alternate animation
6682 if (t->animated == 2) // q2bsp
6683 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6684 else if (rsurface.ent_alttextures && t->anim_total[1])
6685 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6687 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6689 texture->currentframe = t;
6692 // update currentskinframe to be a qw skin or animation frame
6693 if (rsurface.ent_qwskin >= 0)
6695 i = rsurface.ent_qwskin;
6696 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6698 r_qwskincache_size = cl.maxclients;
6700 Mem_Free(r_qwskincache);
6701 r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6703 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6704 R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6705 t->currentskinframe = r_qwskincache[i].skinframe;
6706 if (t->materialshaderpass && t->currentskinframe == NULL)
6707 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6709 else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6710 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6711 if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6712 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6714 t->currentmaterialflags = t->basematerialflags;
6715 t->currentalpha = rsurface.entity->alpha * t->basealpha;
6716 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6717 t->currentalpha *= r_wateralpha.value;
6718 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6719 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6720 if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6721 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6723 // decide on which type of lighting to use for this surface
6724 if (rsurface.entity->render_modellight_forced)
6725 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6726 if (rsurface.entity->render_rtlight_disabled)
6727 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6728 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6730 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6731 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6732 for (q = 0; q < 3; q++)
6734 t->render_glowmod[q] = rsurface.entity->glowmod[q];
6735 t->render_modellight_lightdir[q] = q == 2;
6736 t->render_modellight_ambient[q] = 1;
6737 t->render_modellight_diffuse[q] = 0;
6738 t->render_modellight_specular[q] = 0;
6739 t->render_lightmap_ambient[q] = 0;
6740 t->render_lightmap_diffuse[q] = 0;
6741 t->render_lightmap_specular[q] = 0;
6742 t->render_rtlight_diffuse[q] = 0;
6743 t->render_rtlight_specular[q] = 0;
6746 else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6748 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6749 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6750 for (q = 0; q < 3; q++)
6752 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6753 t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6754 t->render_modellight_lightdir[q] = q == 2;
6755 t->render_modellight_diffuse[q] = 0;
6756 t->render_modellight_specular[q] = 0;
6757 t->render_lightmap_ambient[q] = 0;
6758 t->render_lightmap_diffuse[q] = 0;
6759 t->render_lightmap_specular[q] = 0;
6760 t->render_rtlight_diffuse[q] = 0;
6761 t->render_rtlight_specular[q] = 0;
6764 else if (FAKELIGHT_ENABLED)
6766 // no modellight if using fakelight for the map
6767 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6768 for (q = 0; q < 3; q++)
6770 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6771 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6772 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6773 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6774 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6775 t->render_lightmap_ambient[q] = 0;
6776 t->render_lightmap_diffuse[q] = 0;
6777 t->render_lightmap_specular[q] = 0;
6778 t->render_rtlight_diffuse[q] = 0;
6779 t->render_rtlight_specular[q] = 0;
6782 else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6784 // ambient + single direction light (modellight)
6785 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6786 for (q = 0; q < 3; q++)
6788 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6789 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6790 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6791 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6792 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6793 t->render_lightmap_ambient[q] = 0;
6794 t->render_lightmap_diffuse[q] = 0;
6795 t->render_lightmap_specular[q] = 0;
6796 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6797 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6802 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6803 for (q = 0; q < 3; q++)
6805 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6806 t->render_modellight_lightdir[q] = q == 2;
6807 t->render_modellight_ambient[q] = 0;
6808 t->render_modellight_diffuse[q] = 0;
6809 t->render_modellight_specular[q] = 0;
6810 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6811 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6812 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6813 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6814 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6818 if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6820 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6821 // attribute, we punt it to the lightmap path and hope for the best,
6822 // but lighting doesn't work.
6824 // FIXME: this is fine for effects but CSQC polygons should be subject
6826 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6827 for (q = 0; q < 3; q++)
6829 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6830 t->render_modellight_lightdir[q] = q == 2;
6831 t->render_modellight_ambient[q] = 0;
6832 t->render_modellight_diffuse[q] = 0;
6833 t->render_modellight_specular[q] = 0;
6834 t->render_lightmap_ambient[q] = 0;
6835 t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6836 t->render_lightmap_specular[q] = 0;
6837 t->render_rtlight_diffuse[q] = 0;
6838 t->render_rtlight_specular[q] = 0;
6842 for (q = 0; q < 3; q++)
6844 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6845 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6848 if (rsurface.ent_flags & RENDER_ADDITIVE)
6849 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6850 else if (t->currentalpha < 1)
6851 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6852 // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6853 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6854 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6855 if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6856 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6857 if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6858 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6859 if (t->backgroundshaderpass)
6860 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6861 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6863 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6864 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6867 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6868 if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6870 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6871 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6873 if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6874 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6876 // there is no tcmod
6877 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6879 t->currenttexmatrix = r_waterscrollmatrix;
6880 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6882 else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6884 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6885 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6888 if (t->materialshaderpass)
6889 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6890 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6892 t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6893 if (t->currentskinframe->qpixels)
6894 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6895 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6896 if (!t->basetexture)
6897 t->basetexture = r_texture_notexture;
6898 t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6899 t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6900 t->nmaptexture = t->currentskinframe->nmap;
6901 if (!t->nmaptexture)
6902 t->nmaptexture = r_texture_blanknormalmap;
6903 t->glosstexture = r_texture_black;
6904 t->glowtexture = t->currentskinframe->glow;
6905 t->fogtexture = t->currentskinframe->fog;
6906 t->reflectmasktexture = t->currentskinframe->reflect;
6907 if (t->backgroundshaderpass)
6909 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6910 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6911 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6912 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6913 t->backgroundglosstexture = r_texture_black;
6914 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6915 if (!t->backgroundnmaptexture)
6916 t->backgroundnmaptexture = r_texture_blanknormalmap;
6917 // make sure that if glow is going to be used, both textures are not NULL
6918 if (!t->backgroundglowtexture && t->glowtexture)
6919 t->backgroundglowtexture = r_texture_black;
6920 if (!t->glowtexture && t->backgroundglowtexture)
6921 t->glowtexture = r_texture_black;
6925 t->backgroundbasetexture = r_texture_white;
6926 t->backgroundnmaptexture = r_texture_blanknormalmap;
6927 t->backgroundglosstexture = r_texture_black;
6928 t->backgroundglowtexture = NULL;
6930 t->specularpower = r_shadow_glossexponent.value;
6931 // TODO: store reference values for these in the texture?
6932 if (r_shadow_gloss.integer > 0)
6934 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6936 if (r_shadow_glossintensity.value > 0)
6938 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6939 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6940 specularscale = r_shadow_glossintensity.value;
6943 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6945 t->glosstexture = r_texture_white;
6946 t->backgroundglosstexture = r_texture_white;
6947 specularscale = r_shadow_gloss2intensity.value;
6948 t->specularpower = r_shadow_gloss2exponent.value;
6951 specularscale *= t->specularscalemod;
6952 t->specularpower *= t->specularpowermod;
6954 // lightmaps mode looks bad with dlights using actual texturing, so turn
6955 // off the colormap and glossmap, but leave the normalmap on as it still
6956 // accurately represents the shading involved
6957 if (gl_lightmaps.integer)
6959 t->basetexture = r_texture_grey128;
6960 t->pantstexture = r_texture_black;
6961 t->shirttexture = r_texture_black;
6962 if (gl_lightmaps.integer < 2)
6963 t->nmaptexture = r_texture_blanknormalmap;
6964 t->glosstexture = r_texture_black;
6965 t->glowtexture = NULL;
6966 t->fogtexture = NULL;
6967 t->reflectmasktexture = NULL;
6968 t->backgroundbasetexture = NULL;
6969 if (gl_lightmaps.integer < 2)
6970 t->backgroundnmaptexture = r_texture_blanknormalmap;
6971 t->backgroundglosstexture = r_texture_black;
6972 t->backgroundglowtexture = NULL;
6974 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6977 if (specularscale != 1.0f)
6979 for (q = 0; q < 3; q++)
6981 t->render_modellight_specular[q] *= specularscale;
6982 t->render_lightmap_specular[q] *= specularscale;
6983 t->render_rtlight_specular[q] *= specularscale;
6987 t->currentnumlayers = 0;
6988 if (t->currentmaterialflags & MATERIALFLAG_WALL)
6990 int blendfunc1, blendfunc2;
6992 if (t->currentmaterialflags & MATERIALFLAG_ADD)
6994 blendfunc1 = GL_SRC_ALPHA;
6995 blendfunc2 = GL_ONE;
6997 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6999 blendfunc1 = GL_SRC_ALPHA;
7000 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7002 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7004 blendfunc1 = t->customblendfunc[0];
7005 blendfunc2 = t->customblendfunc[1];
7009 blendfunc1 = GL_ONE;
7010 blendfunc2 = GL_ZERO;
7012 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7013 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7015 // basic lit geometry
7016 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7017 // add pants/shirt if needed
7018 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7019 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);
7020 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7021 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);
7025 // basic lit geometry
7026 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);
7027 // add pants/shirt if needed
7028 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7029 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);
7030 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7031 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);
7032 // now add ambient passes if needed
7033 if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7035 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);
7036 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7037 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);
7038 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7039 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);
7042 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7043 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);
7044 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7046 // if this is opaque use alpha blend which will darken the earlier
7049 // if this is an alpha blended material, all the earlier passes
7050 // were darkened by fog already, so we only need to add the fog
7051 // color ontop through the fog mask texture
7053 // if this is an additive blended material, all the earlier passes
7054 // were darkened by fog already, and we should not add fog color
7055 // (because the background was not darkened, there is no fog color
7056 // that was lost behind it).
7057 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);
7064 rsurfacestate_t rsurface;
7066 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7068 dp_model_t *model = ent->model;
7069 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7071 rsurface.entity = (entity_render_t *)ent;
7072 rsurface.skeleton = ent->skeleton;
7073 memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7074 rsurface.ent_skinnum = ent->skinnum;
7075 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;
7076 rsurface.ent_flags = ent->flags;
7077 if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7078 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7079 rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7080 rsurface.matrix = ent->matrix;
7081 rsurface.inversematrix = ent->inversematrix;
7082 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7083 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7084 R_EntityMatrix(&rsurface.matrix);
7085 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7086 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7087 rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7088 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7089 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7090 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7091 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7092 rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7093 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7094 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7095 if (ent->model->brush.submodel && !prepass)
7097 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7098 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7100 // if the animcache code decided it should use the shader path, skip the deform step
7101 rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7102 rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7103 rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7104 rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7105 rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7106 if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7108 if (ent->animcache_vertex3f)
7110 r_refdef.stats[r_stat_batch_entitycache_count]++;
7111 r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7112 r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7113 r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7114 rsurface.modelvertex3f = ent->animcache_vertex3f;
7115 rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7116 rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7117 rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7118 rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7119 rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7120 rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7121 rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7122 rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7123 rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7124 rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7125 rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7127 else if (wanttangents)
7129 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7130 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7131 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7132 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7133 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7134 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7135 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7136 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7137 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7138 rsurface.modelvertex3f_vertexbuffer = NULL;
7139 rsurface.modelvertex3f_bufferoffset = 0;
7140 rsurface.modelvertex3f_vertexbuffer = 0;
7141 rsurface.modelvertex3f_bufferoffset = 0;
7142 rsurface.modelsvector3f_vertexbuffer = 0;
7143 rsurface.modelsvector3f_bufferoffset = 0;
7144 rsurface.modeltvector3f_vertexbuffer = 0;
7145 rsurface.modeltvector3f_bufferoffset = 0;
7146 rsurface.modelnormal3f_vertexbuffer = 0;
7147 rsurface.modelnormal3f_bufferoffset = 0;
7149 else if (wantnormals)
7151 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7152 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7153 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7154 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7155 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7156 rsurface.modelsvector3f = NULL;
7157 rsurface.modeltvector3f = NULL;
7158 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7159 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7160 rsurface.modelvertex3f_vertexbuffer = NULL;
7161 rsurface.modelvertex3f_bufferoffset = 0;
7162 rsurface.modelvertex3f_vertexbuffer = 0;
7163 rsurface.modelvertex3f_bufferoffset = 0;
7164 rsurface.modelsvector3f_vertexbuffer = 0;
7165 rsurface.modelsvector3f_bufferoffset = 0;
7166 rsurface.modeltvector3f_vertexbuffer = 0;
7167 rsurface.modeltvector3f_bufferoffset = 0;
7168 rsurface.modelnormal3f_vertexbuffer = 0;
7169 rsurface.modelnormal3f_bufferoffset = 0;
7173 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7174 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7175 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7176 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7177 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7178 rsurface.modelsvector3f = NULL;
7179 rsurface.modeltvector3f = NULL;
7180 rsurface.modelnormal3f = NULL;
7181 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7182 rsurface.modelvertex3f_vertexbuffer = NULL;
7183 rsurface.modelvertex3f_bufferoffset = 0;
7184 rsurface.modelvertex3f_vertexbuffer = 0;
7185 rsurface.modelvertex3f_bufferoffset = 0;
7186 rsurface.modelsvector3f_vertexbuffer = 0;
7187 rsurface.modelsvector3f_bufferoffset = 0;
7188 rsurface.modeltvector3f_vertexbuffer = 0;
7189 rsurface.modeltvector3f_bufferoffset = 0;
7190 rsurface.modelnormal3f_vertexbuffer = 0;
7191 rsurface.modelnormal3f_bufferoffset = 0;
7193 rsurface.modelgeneratedvertex = true;
7197 if (rsurface.entityskeletaltransform3x4)
7199 r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7200 r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7201 r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7202 r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7206 r_refdef.stats[r_stat_batch_entitystatic_count]++;
7207 r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7208 r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7209 r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7211 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
7212 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7213 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7214 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7215 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7216 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7217 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7218 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7219 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7220 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
7221 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7222 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7223 rsurface.modelgeneratedvertex = false;
7225 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
7226 rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7227 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7228 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
7229 rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7230 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7231 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
7232 rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7233 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7234 rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7235 rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7236 rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7237 rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7238 rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7239 rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7240 rsurface.modelelement3i = model->surfmesh.data_element3i;
7241 rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7242 rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7243 rsurface.modelelement3s = model->surfmesh.data_element3s;
7244 rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7245 rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7246 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7247 rsurface.modelnumvertices = model->surfmesh.num_vertices;
7248 rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7249 rsurface.modelsurfaces = model->data_surfaces;
7250 rsurface.batchgeneratedvertex = false;
7251 rsurface.batchfirstvertex = 0;
7252 rsurface.batchnumvertices = 0;
7253 rsurface.batchfirsttriangle = 0;
7254 rsurface.batchnumtriangles = 0;
7255 rsurface.batchvertex3f = NULL;
7256 rsurface.batchvertex3f_vertexbuffer = NULL;
7257 rsurface.batchvertex3f_bufferoffset = 0;
7258 rsurface.batchsvector3f = NULL;
7259 rsurface.batchsvector3f_vertexbuffer = NULL;
7260 rsurface.batchsvector3f_bufferoffset = 0;
7261 rsurface.batchtvector3f = NULL;
7262 rsurface.batchtvector3f_vertexbuffer = NULL;
7263 rsurface.batchtvector3f_bufferoffset = 0;
7264 rsurface.batchnormal3f = NULL;
7265 rsurface.batchnormal3f_vertexbuffer = NULL;
7266 rsurface.batchnormal3f_bufferoffset = 0;
7267 rsurface.batchlightmapcolor4f = NULL;
7268 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7269 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7270 rsurface.batchtexcoordtexture2f = NULL;
7271 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7272 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7273 rsurface.batchtexcoordlightmap2f = NULL;
7274 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7275 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7276 rsurface.batchskeletalindex4ub = NULL;
7277 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7278 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7279 rsurface.batchskeletalweight4ub = NULL;
7280 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7281 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7282 rsurface.batchelement3i = NULL;
7283 rsurface.batchelement3i_indexbuffer = NULL;
7284 rsurface.batchelement3i_bufferoffset = 0;
7285 rsurface.batchelement3s = NULL;
7286 rsurface.batchelement3s_indexbuffer = NULL;
7287 rsurface.batchelement3s_bufferoffset = 0;
7288 rsurface.forcecurrenttextureupdate = false;
7291 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)
7293 rsurface.entity = r_refdef.scene.worldentity;
7294 rsurface.skeleton = NULL;
7295 rsurface.ent_skinnum = 0;
7296 rsurface.ent_qwskin = -1;
7297 rsurface.ent_flags = entflags;
7298 rsurface.shadertime = r_refdef.scene.time - shadertime;
7299 rsurface.modelnumvertices = numvertices;
7300 rsurface.modelnumtriangles = numtriangles;
7301 rsurface.matrix = *matrix;
7302 rsurface.inversematrix = *inversematrix;
7303 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7304 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7305 R_EntityMatrix(&rsurface.matrix);
7306 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7307 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7308 rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7309 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7310 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7311 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7312 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7313 rsurface.frameblend[0].lerp = 1;
7314 rsurface.ent_alttextures = false;
7315 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7316 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7317 rsurface.entityskeletaltransform3x4 = NULL;
7318 rsurface.entityskeletaltransform3x4buffer = NULL;
7319 rsurface.entityskeletaltransform3x4offset = 0;
7320 rsurface.entityskeletaltransform3x4size = 0;
7321 rsurface.entityskeletalnumtransforms = 0;
7322 r_refdef.stats[r_stat_batch_entitycustom_count]++;
7323 r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7324 r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7325 r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7328 rsurface.modelvertex3f = (float *)vertex3f;
7329 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7330 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7331 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7333 else if (wantnormals)
7335 rsurface.modelvertex3f = (float *)vertex3f;
7336 rsurface.modelsvector3f = NULL;
7337 rsurface.modeltvector3f = NULL;
7338 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7342 rsurface.modelvertex3f = (float *)vertex3f;
7343 rsurface.modelsvector3f = NULL;
7344 rsurface.modeltvector3f = NULL;
7345 rsurface.modelnormal3f = NULL;
7347 rsurface.modelvertex3f_vertexbuffer = 0;
7348 rsurface.modelvertex3f_bufferoffset = 0;
7349 rsurface.modelsvector3f_vertexbuffer = 0;
7350 rsurface.modelsvector3f_bufferoffset = 0;
7351 rsurface.modeltvector3f_vertexbuffer = 0;
7352 rsurface.modeltvector3f_bufferoffset = 0;
7353 rsurface.modelnormal3f_vertexbuffer = 0;
7354 rsurface.modelnormal3f_bufferoffset = 0;
7355 rsurface.modelgeneratedvertex = true;
7356 rsurface.modellightmapcolor4f = (float *)color4f;
7357 rsurface.modellightmapcolor4f_vertexbuffer = 0;
7358 rsurface.modellightmapcolor4f_bufferoffset = 0;
7359 rsurface.modeltexcoordtexture2f = (float *)texcoord2f;
7360 rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7361 rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7362 rsurface.modeltexcoordlightmap2f = NULL;
7363 rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7364 rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7365 rsurface.modelskeletalindex4ub = NULL;
7366 rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7367 rsurface.modelskeletalindex4ub_bufferoffset = 0;
7368 rsurface.modelskeletalweight4ub = NULL;
7369 rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7370 rsurface.modelskeletalweight4ub_bufferoffset = 0;
7371 rsurface.modelelement3i = (int *)element3i;
7372 rsurface.modelelement3i_indexbuffer = NULL;
7373 rsurface.modelelement3i_bufferoffset = 0;
7374 rsurface.modelelement3s = (unsigned short *)element3s;
7375 rsurface.modelelement3s_indexbuffer = NULL;
7376 rsurface.modelelement3s_bufferoffset = 0;
7377 rsurface.modellightmapoffsets = NULL;
7378 rsurface.modelsurfaces = NULL;
7379 rsurface.batchgeneratedvertex = false;
7380 rsurface.batchfirstvertex = 0;
7381 rsurface.batchnumvertices = 0;
7382 rsurface.batchfirsttriangle = 0;
7383 rsurface.batchnumtriangles = 0;
7384 rsurface.batchvertex3f = NULL;
7385 rsurface.batchvertex3f_vertexbuffer = NULL;
7386 rsurface.batchvertex3f_bufferoffset = 0;
7387 rsurface.batchsvector3f = NULL;
7388 rsurface.batchsvector3f_vertexbuffer = NULL;
7389 rsurface.batchsvector3f_bufferoffset = 0;
7390 rsurface.batchtvector3f = NULL;
7391 rsurface.batchtvector3f_vertexbuffer = NULL;
7392 rsurface.batchtvector3f_bufferoffset = 0;
7393 rsurface.batchnormal3f = NULL;
7394 rsurface.batchnormal3f_vertexbuffer = NULL;
7395 rsurface.batchnormal3f_bufferoffset = 0;
7396 rsurface.batchlightmapcolor4f = NULL;
7397 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7398 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7399 rsurface.batchtexcoordtexture2f = NULL;
7400 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7401 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7402 rsurface.batchtexcoordlightmap2f = NULL;
7403 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7404 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7405 rsurface.batchskeletalindex4ub = NULL;
7406 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7407 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7408 rsurface.batchskeletalweight4ub = NULL;
7409 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7410 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7411 rsurface.batchelement3i = NULL;
7412 rsurface.batchelement3i_indexbuffer = NULL;
7413 rsurface.batchelement3i_bufferoffset = 0;
7414 rsurface.batchelement3s = NULL;
7415 rsurface.batchelement3s_indexbuffer = NULL;
7416 rsurface.batchelement3s_bufferoffset = 0;
7417 rsurface.forcecurrenttextureupdate = true;
7419 if (rsurface.modelnumvertices && rsurface.modelelement3i)
7421 if ((wantnormals || wanttangents) && !normal3f)
7423 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7424 Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7426 if (wanttangents && !svector3f)
7428 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7429 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7430 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7435 float RSurf_FogPoint(const float *v)
7437 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7438 float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7439 float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7440 float FogHeightFade = r_refdef.fogheightfade;
7442 unsigned int fogmasktableindex;
7443 if (r_refdef.fogplaneviewabove)
7444 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7446 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7447 fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7448 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7451 float RSurf_FogVertex(const float *v)
7453 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7454 float FogPlaneViewDist = rsurface.fogplaneviewdist;
7455 float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7456 float FogHeightFade = rsurface.fogheightfade;
7458 unsigned int fogmasktableindex;
7459 if (r_refdef.fogplaneviewabove)
7460 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7462 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7463 fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7464 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7467 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7470 for (i = 0;i < numelements;i++)
7471 outelement3i[i] = inelement3i[i] + adjust;
7474 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7475 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7483 int surfacefirsttriangle;
7484 int surfacenumtriangles;
7485 int surfacefirstvertex;
7486 int surfaceendvertex;
7487 int surfacenumvertices;
7488 int batchnumsurfaces = texturenumsurfaces;
7489 int batchnumvertices;
7490 int batchnumtriangles;
7493 qboolean dynamicvertex;
7496 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7499 q3shaderinfo_deform_t *deform;
7500 const msurface_t *surface, *firstsurface;
7501 if (!texturenumsurfaces)
7503 // find vertex range of this surface batch
7505 firstsurface = texturesurfacelist[0];
7506 firsttriangle = firstsurface->num_firsttriangle;
7507 batchnumvertices = 0;
7508 batchnumtriangles = 0;
7509 firstvertex = endvertex = firstsurface->num_firstvertex;
7510 for (i = 0;i < texturenumsurfaces;i++)
7512 surface = texturesurfacelist[i];
7513 if (surface != firstsurface + i)
7515 surfacefirstvertex = surface->num_firstvertex;
7516 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7517 surfacenumvertices = surface->num_vertices;
7518 surfacenumtriangles = surface->num_triangles;
7519 if (firstvertex > surfacefirstvertex)
7520 firstvertex = surfacefirstvertex;
7521 if (endvertex < surfaceendvertex)
7522 endvertex = surfaceendvertex;
7523 batchnumvertices += surfacenumvertices;
7524 batchnumtriangles += surfacenumtriangles;
7527 r_refdef.stats[r_stat_batch_batches]++;
7529 r_refdef.stats[r_stat_batch_withgaps]++;
7530 r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7531 r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7532 r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7534 // we now know the vertex range used, and if there are any gaps in it
7535 rsurface.batchfirstvertex = firstvertex;
7536 rsurface.batchnumvertices = endvertex - firstvertex;
7537 rsurface.batchfirsttriangle = firsttriangle;
7538 rsurface.batchnumtriangles = batchnumtriangles;
7540 // check if any dynamic vertex processing must occur
7541 dynamicvertex = false;
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];
7830 // upload buffer data for the copytriangles batch
7831 if (rsurface.batchelement3s)
7832 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7833 else if (rsurface.batchelement3i)
7834 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7838 r_refdef.stats[r_stat_batch_fast_batches] += 1;
7839 r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7840 r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7841 r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7846 // something needs software processing, do it for real...
7847 // we only directly handle separate array data in this case and then
7848 // generate interleaved data if needed...
7849 rsurface.batchgeneratedvertex = true;
7850 r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7851 r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7852 r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7853 r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7855 // now copy the vertex data into a combined array and make an index array
7856 // (this is what Quake3 does all the time)
7857 // we also apply any skeletal animation here that would have been done in
7858 // the vertex shader, because most of the dynamic vertex animation cases
7859 // need actual vertex positions and normals
7860 //if (dynamicvertex)
7862 rsurface.batchvertex3f = NULL;
7863 rsurface.batchvertex3f_vertexbuffer = NULL;
7864 rsurface.batchvertex3f_bufferoffset = 0;
7865 rsurface.batchsvector3f = NULL;
7866 rsurface.batchsvector3f_vertexbuffer = NULL;
7867 rsurface.batchsvector3f_bufferoffset = 0;
7868 rsurface.batchtvector3f = NULL;
7869 rsurface.batchtvector3f_vertexbuffer = NULL;
7870 rsurface.batchtvector3f_bufferoffset = 0;
7871 rsurface.batchnormal3f = NULL;
7872 rsurface.batchnormal3f_vertexbuffer = NULL;
7873 rsurface.batchnormal3f_bufferoffset = 0;
7874 rsurface.batchlightmapcolor4f = NULL;
7875 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7876 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7877 rsurface.batchtexcoordtexture2f = NULL;
7878 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7879 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7880 rsurface.batchtexcoordlightmap2f = NULL;
7881 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7882 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7883 rsurface.batchskeletalindex4ub = NULL;
7884 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7885 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7886 rsurface.batchskeletalweight4ub = NULL;
7887 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7888 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7889 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7890 rsurface.batchelement3i_indexbuffer = NULL;
7891 rsurface.batchelement3i_bufferoffset = 0;
7892 rsurface.batchelement3s = NULL;
7893 rsurface.batchelement3s_indexbuffer = NULL;
7894 rsurface.batchelement3s_bufferoffset = 0;
7895 rsurface.batchskeletaltransform3x4buffer = NULL;
7896 rsurface.batchskeletaltransform3x4offset = 0;
7897 rsurface.batchskeletaltransform3x4size = 0;
7898 // we'll only be setting up certain arrays as needed
7899 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7900 rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7901 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7902 rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7903 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7905 rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7906 rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7908 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7909 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7910 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7911 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7912 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7913 rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7914 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7916 rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7917 rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7921 for (i = 0;i < texturenumsurfaces;i++)
7923 surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7924 surfacenumvertices = texturesurfacelist[i]->num_vertices;
7925 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7926 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7927 // copy only the data requested
7928 if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7930 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7932 if (rsurface.batchvertex3f)
7933 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7935 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7937 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7939 if (rsurface.modelnormal3f)
7940 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7942 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7944 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7946 if (rsurface.modelsvector3f)
7948 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7949 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7953 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7954 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7957 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7959 if (rsurface.modellightmapcolor4f)
7960 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7962 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7964 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7966 if (rsurface.modeltexcoordtexture2f)
7967 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7969 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7971 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7973 if (rsurface.modeltexcoordlightmap2f)
7974 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7976 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7978 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7980 if (rsurface.modelskeletalindex4ub)
7982 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7983 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7987 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7988 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7989 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7990 for (j = 0;j < surfacenumvertices;j++)
7995 RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7996 numvertices += surfacenumvertices;
7997 numtriangles += surfacenumtriangles;
8000 // generate a 16bit index array as well if possible
8001 // (in general, dynamic batches fit)
8002 if (numvertices <= 65536)
8004 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8005 for (i = 0;i < numtriangles*3;i++)
8006 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8009 // since we've copied everything, the batch now starts at 0
8010 rsurface.batchfirstvertex = 0;
8011 rsurface.batchnumvertices = batchnumvertices;
8012 rsurface.batchfirsttriangle = 0;
8013 rsurface.batchnumtriangles = batchnumtriangles;
8016 // apply skeletal animation that would have been done in the vertex shader
8017 if (rsurface.batchskeletaltransform3x4)
8019 const unsigned char *si;
8020 const unsigned char *sw;
8022 const float *b = rsurface.batchskeletaltransform3x4;
8023 float *vp, *vs, *vt, *vn;
8025 float m[3][4], n[3][4];
8026 float tp[3], ts[3], tt[3], tn[3];
8027 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8028 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8029 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8030 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8031 si = rsurface.batchskeletalindex4ub;
8032 sw = rsurface.batchskeletalweight4ub;
8033 vp = rsurface.batchvertex3f;
8034 vs = rsurface.batchsvector3f;
8035 vt = rsurface.batchtvector3f;
8036 vn = rsurface.batchnormal3f;
8037 memset(m[0], 0, sizeof(m));
8038 memset(n[0], 0, sizeof(n));
8039 for (i = 0;i < batchnumvertices;i++)
8041 t[0] = b + si[0]*12;
8044 // common case - only one matrix
8058 else if (sw[2] + sw[3])
8061 t[1] = b + si[1]*12;
8062 t[2] = b + si[2]*12;
8063 t[3] = b + si[3]*12;
8064 w[0] = sw[0] * (1.0f / 255.0f);
8065 w[1] = sw[1] * (1.0f / 255.0f);
8066 w[2] = sw[2] * (1.0f / 255.0f);
8067 w[3] = sw[3] * (1.0f / 255.0f);
8068 // blend the matrices
8069 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8070 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8071 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8072 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8073 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8074 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8075 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8076 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8077 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8078 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8079 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8080 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8085 t[1] = b + si[1]*12;
8086 w[0] = sw[0] * (1.0f / 255.0f);
8087 w[1] = sw[1] * (1.0f / 255.0f);
8088 // blend the matrices
8089 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8090 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8091 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8092 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8093 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8094 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8095 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8096 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8097 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8098 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8099 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8100 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8104 // modify the vertex
8106 vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8107 vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8108 vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8112 // the normal transformation matrix is a set of cross products...
8113 CrossProduct(m[1], m[2], n[0]);
8114 CrossProduct(m[2], m[0], n[1]);
8115 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8117 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8118 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8119 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8120 VectorNormalize(vn);
8125 vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8126 vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8127 vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8128 VectorNormalize(vs);
8131 vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8132 vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8133 vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8134 VectorNormalize(vt);
8139 rsurface.batchskeletaltransform3x4 = NULL;
8140 rsurface.batchskeletalnumtransforms = 0;
8143 // q1bsp surfaces rendered in vertex color mode have to have colors
8144 // calculated based on lightstyles
8145 if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8147 // generate color arrays for the surfaces in this list
8152 const unsigned char *lm;
8153 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8154 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8155 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8157 for (i = 0;i < texturenumsurfaces;i++)
8159 surface = texturesurfacelist[i];
8160 offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8161 surfacenumvertices = surface->num_vertices;
8162 if (surface->lightmapinfo->samples)
8164 for (j = 0;j < surfacenumvertices;j++)
8166 lm = surface->lightmapinfo->samples + offsets[j];
8167 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8168 VectorScale(lm, scale, c);
8169 if (surface->lightmapinfo->styles[1] != 255)
8171 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8173 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8174 VectorMA(c, scale, lm, c);
8175 if (surface->lightmapinfo->styles[2] != 255)
8178 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8179 VectorMA(c, scale, lm, c);
8180 if (surface->lightmapinfo->styles[3] != 255)
8183 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8184 VectorMA(c, scale, lm, c);
8191 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);
8197 for (j = 0;j < surfacenumvertices;j++)
8199 Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8206 // if vertices are deformed (sprite flares and things in maps, possibly
8207 // water waves, bulges and other deformations), modify the copied vertices
8209 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8212 switch (deform->deform)
8215 case Q3DEFORM_PROJECTIONSHADOW:
8216 case Q3DEFORM_TEXT0:
8217 case Q3DEFORM_TEXT1:
8218 case Q3DEFORM_TEXT2:
8219 case Q3DEFORM_TEXT3:
8220 case Q3DEFORM_TEXT4:
8221 case Q3DEFORM_TEXT5:
8222 case Q3DEFORM_TEXT6:
8223 case Q3DEFORM_TEXT7:
8226 case Q3DEFORM_AUTOSPRITE:
8227 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8228 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8229 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8230 VectorNormalize(newforward);
8231 VectorNormalize(newright);
8232 VectorNormalize(newup);
8233 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8234 // rsurface.batchvertex3f_vertexbuffer = NULL;
8235 // rsurface.batchvertex3f_bufferoffset = 0;
8236 // rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8237 // rsurface.batchsvector3f_vertexbuffer = NULL;
8238 // rsurface.batchsvector3f_bufferoffset = 0;
8239 // rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8240 // rsurface.batchtvector3f_vertexbuffer = NULL;
8241 // rsurface.batchtvector3f_bufferoffset = 0;
8242 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8243 // rsurface.batchnormal3f_vertexbuffer = NULL;
8244 // rsurface.batchnormal3f_bufferoffset = 0;
8245 // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8246 if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8247 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8248 if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8249 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);
8250 // a single autosprite surface can contain multiple sprites...
8251 for (j = 0;j < batchnumvertices - 3;j += 4)
8253 VectorClear(center);
8254 for (i = 0;i < 4;i++)
8255 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8256 VectorScale(center, 0.25f, center);
8257 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8258 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8259 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8260 for (i = 0;i < 4;i++)
8262 VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8263 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8266 // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8267 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8268 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);
8270 case Q3DEFORM_AUTOSPRITE2:
8271 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8272 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8273 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8274 VectorNormalize(newforward);
8275 VectorNormalize(newright);
8276 VectorNormalize(newup);
8277 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8278 // rsurface.batchvertex3f_vertexbuffer = NULL;
8279 // rsurface.batchvertex3f_bufferoffset = 0;
8281 const float *v1, *v2;
8291 memset(shortest, 0, sizeof(shortest));
8292 // a single autosprite surface can contain multiple sprites...
8293 for (j = 0;j < batchnumvertices - 3;j += 4)
8295 VectorClear(center);
8296 for (i = 0;i < 4;i++)
8297 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8298 VectorScale(center, 0.25f, center);
8299 // find the two shortest edges, then use them to define the
8300 // axis vectors for rotating around the central axis
8301 for (i = 0;i < 6;i++)
8303 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8304 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8305 l = VectorDistance2(v1, v2);
8306 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8308 l += (1.0f / 1024.0f);
8309 if (shortest[0].length2 > l || i == 0)
8311 shortest[1] = shortest[0];
8312 shortest[0].length2 = l;
8313 shortest[0].v1 = v1;
8314 shortest[0].v2 = v2;
8316 else if (shortest[1].length2 > l || i == 1)
8318 shortest[1].length2 = l;
8319 shortest[1].v1 = v1;
8320 shortest[1].v2 = v2;
8323 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8324 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8325 // this calculates the right vector from the shortest edge
8326 // and the up vector from the edge midpoints
8327 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8328 VectorNormalize(right);
8329 VectorSubtract(end, start, up);
8330 VectorNormalize(up);
8331 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8332 VectorSubtract(rsurface.localvieworigin, center, forward);
8333 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8334 VectorNegate(forward, forward);
8335 VectorReflect(forward, 0, up, forward);
8336 VectorNormalize(forward);
8337 CrossProduct(up, forward, newright);
8338 VectorNormalize(newright);
8339 // rotate the quad around the up axis vector, this is made
8340 // especially easy by the fact we know the quad is flat,
8341 // so we only have to subtract the center position and
8342 // measure distance along the right vector, and then
8343 // multiply that by the newright vector and add back the
8345 // we also need to subtract the old position to undo the
8346 // displacement from the center, which we do with a
8347 // DotProduct, the subtraction/addition of center is also
8348 // optimized into DotProducts here
8349 l = DotProduct(right, center);
8350 for (i = 0;i < 4;i++)
8352 v1 = rsurface.batchvertex3f + 3*(j+i);
8353 f = DotProduct(right, v1) - l;
8354 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8358 if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8360 // rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8361 // rsurface.batchnormal3f_vertexbuffer = NULL;
8362 // rsurface.batchnormal3f_bufferoffset = 0;
8363 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8365 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8367 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8368 // rsurface.batchsvector3f_vertexbuffer = NULL;
8369 // rsurface.batchsvector3f_bufferoffset = 0;
8370 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8371 // rsurface.batchtvector3f_vertexbuffer = NULL;
8372 // rsurface.batchtvector3f_bufferoffset = 0;
8373 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);
8376 case Q3DEFORM_NORMAL:
8377 // deform the normals to make reflections wavey
8378 rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8379 rsurface.batchnormal3f_vertexbuffer = NULL;
8380 rsurface.batchnormal3f_bufferoffset = 0;
8381 for (j = 0;j < batchnumvertices;j++)
8384 float *normal = rsurface.batchnormal3f + 3*j;
8385 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8386 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8387 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8388 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8389 VectorNormalize(normal);
8391 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8393 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8394 // rsurface.batchsvector3f_vertexbuffer = NULL;
8395 // rsurface.batchsvector3f_bufferoffset = 0;
8396 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8397 // rsurface.batchtvector3f_vertexbuffer = NULL;
8398 // rsurface.batchtvector3f_bufferoffset = 0;
8399 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);
8403 // deform vertex array to make wavey water and flags and such
8404 waveparms[0] = deform->waveparms[0];
8405 waveparms[1] = deform->waveparms[1];
8406 waveparms[2] = deform->waveparms[2];
8407 waveparms[3] = deform->waveparms[3];
8408 if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8409 break; // if wavefunc is a nop, don't make a dynamic vertex array
8410 // this is how a divisor of vertex influence on deformation
8411 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8412 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8413 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8414 // rsurface.batchvertex3f_vertexbuffer = NULL;
8415 // rsurface.batchvertex3f_bufferoffset = 0;
8416 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8417 // rsurface.batchnormal3f_vertexbuffer = NULL;
8418 // rsurface.batchnormal3f_bufferoffset = 0;
8419 for (j = 0;j < batchnumvertices;j++)
8421 // if the wavefunc depends on time, evaluate it per-vertex
8424 waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8425 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8427 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8429 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8430 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8431 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8433 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8434 // rsurface.batchsvector3f_vertexbuffer = NULL;
8435 // rsurface.batchsvector3f_bufferoffset = 0;
8436 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8437 // rsurface.batchtvector3f_vertexbuffer = NULL;
8438 // rsurface.batchtvector3f_bufferoffset = 0;
8439 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);
8442 case Q3DEFORM_BULGE:
8443 // deform vertex array to make the surface have moving bulges
8444 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8445 // rsurface.batchvertex3f_vertexbuffer = NULL;
8446 // rsurface.batchvertex3f_bufferoffset = 0;
8447 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8448 // rsurface.batchnormal3f_vertexbuffer = NULL;
8449 // rsurface.batchnormal3f_bufferoffset = 0;
8450 for (j = 0;j < batchnumvertices;j++)
8452 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8453 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8455 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8456 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8457 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8459 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8460 // rsurface.batchsvector3f_vertexbuffer = NULL;
8461 // rsurface.batchsvector3f_bufferoffset = 0;
8462 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8463 // rsurface.batchtvector3f_vertexbuffer = NULL;
8464 // rsurface.batchtvector3f_bufferoffset = 0;
8465 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);
8469 // deform vertex array
8470 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8471 break; // if wavefunc is a nop, don't make a dynamic vertex array
8472 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8473 VectorScale(deform->parms, scale, waveparms);
8474 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8475 // rsurface.batchvertex3f_vertexbuffer = NULL;
8476 // rsurface.batchvertex3f_bufferoffset = 0;
8477 for (j = 0;j < batchnumvertices;j++)
8478 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8483 if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8485 // generate texcoords based on the chosen texcoord source
8486 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8489 case Q3TCGEN_TEXTURE:
8491 case Q3TCGEN_LIGHTMAP:
8492 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8493 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8494 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8495 if (rsurface.batchtexcoordlightmap2f)
8496 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8498 case Q3TCGEN_VECTOR:
8499 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8500 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8501 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8502 for (j = 0;j < batchnumvertices;j++)
8504 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8505 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8508 case Q3TCGEN_ENVIRONMENT:
8509 // make environment reflections using a spheremap
8510 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8511 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8512 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8513 for (j = 0;j < batchnumvertices;j++)
8515 // identical to Q3A's method, but executed in worldspace so
8516 // carried models can be shiny too
8518 float viewer[3], d, reflected[3], worldreflected[3];
8520 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8521 // VectorNormalize(viewer);
8523 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8525 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8526 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8527 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8528 // note: this is proportinal to viewer, so we can normalize later
8530 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8531 VectorNormalize(worldreflected);
8533 // note: this sphere map only uses world x and z!
8534 // so positive and negative y will LOOK THE SAME.
8535 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8536 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8540 // the only tcmod that needs software vertex processing is turbulent, so
8541 // check for it here and apply the changes if needed
8542 // and we only support that as the first one
8543 // (handling a mixture of turbulent and other tcmods would be problematic
8544 // without punting it entirely to a software path)
8545 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8547 amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8548 animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8549 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8550 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8551 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8552 for (j = 0;j < batchnumvertices;j++)
8554 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);
8555 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8560 // upload buffer data for the dynamic batch
8561 if (rsurface.batchvertex3f)
8562 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8563 if (rsurface.batchsvector3f)
8564 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8565 if (rsurface.batchtvector3f)
8566 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8567 if (rsurface.batchnormal3f)
8568 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8569 if (rsurface.batchlightmapcolor4f)
8570 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8571 if (rsurface.batchtexcoordtexture2f)
8572 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8573 if (rsurface.batchtexcoordlightmap2f)
8574 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8575 if (rsurface.batchskeletalindex4ub)
8576 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8577 if (rsurface.batchskeletalweight4ub)
8578 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8579 if (rsurface.batchelement3s)
8580 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8581 else if (rsurface.batchelement3i)
8582 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8585 void RSurf_DrawBatch(void)
8587 // sometimes a zero triangle surface (usually a degenerate patch) makes it
8588 // through the pipeline, killing it earlier in the pipeline would have
8589 // per-surface overhead rather than per-batch overhead, so it's best to
8590 // reject it here, before it hits glDraw.
8591 if (rsurface.batchnumtriangles == 0)
8594 // batch debugging code
8595 if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8601 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8602 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8605 for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8607 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8609 if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8610 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);
8617 if (rsurface.batchmultidraw)
8619 // issue multiple draws rather than copying index data
8620 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8621 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8622 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8623 for (i = 0;i < numsurfaces;)
8625 // combine consecutive surfaces as one draw
8626 for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8627 if (surfacelist[j] != surfacelist[k] + 1)
8629 firstvertex = surfacelist[i]->num_firstvertex;
8630 endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8631 firsttriangle = surfacelist[i]->num_firsttriangle;
8632 endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8633 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);
8639 // there is only one consecutive run of index data (may have been combined)
8640 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);
8644 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8646 // pick the closest matching water plane
8647 int planeindex, vertexindex, bestplaneindex = -1;
8651 r_waterstate_waterplane_t *p;
8652 qboolean prepared = false;
8654 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8656 if(p->camera_entity != rsurface.texture->camera_entity)
8661 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8663 if(rsurface.batchnumvertices == 0)
8666 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8668 Matrix4x4_Transform(&rsurface.matrix, v, vert);
8669 d += fabs(PlaneDiff(vert, &p->plane));
8671 if (bestd > d || bestplaneindex < 0)
8674 bestplaneindex = planeindex;
8677 return bestplaneindex;
8678 // NOTE: this MAY return a totally unrelated water plane; we can ignore
8679 // this situation though, as it might be better to render single larger
8680 // batches with useless stuff (backface culled for example) than to
8681 // render multiple smaller batches
8684 void RSurf_SetupDepthAndCulling(void)
8686 // submodels are biased to avoid z-fighting with world surfaces that they
8687 // may be exactly overlapping (avoids z-fighting artifacts on certain
8688 // doors and things in Quake maps)
8689 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8690 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8691 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8692 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8695 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8698 // transparent sky would be ridiculous
8699 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8701 R_SetupShader_Generic_NoTexture(false, false);
8702 skyrenderlater = true;
8703 RSurf_SetupDepthAndCulling();
8706 // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8707 if (r_sky_scissor.integer)
8709 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8710 for (i = 0; i < texturenumsurfaces; i++)
8712 const msurface_t *surf = texturesurfacelist[i];
8715 float mins[3], maxs[3];
8717 for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8719 Matrix4x4_Transform(&rsurface.matrix, v, p);
8722 if (mins[0] > p[0]) mins[0] = p[0];
8723 if (mins[1] > p[1]) mins[1] = p[1];
8724 if (mins[2] > p[2]) mins[2] = p[2];
8725 if (maxs[0] < p[0]) maxs[0] = p[0];
8726 if (maxs[1] < p[1]) maxs[1] = p[1];
8727 if (maxs[2] < p[2]) maxs[2] = p[2];
8731 VectorCopy(p, mins);
8732 VectorCopy(p, maxs);
8735 if (!R_ScissorForBBox(mins, maxs, scissor))
8739 if (skyscissor[0] > scissor[0])
8741 skyscissor[2] += skyscissor[0] - scissor[0];
8742 skyscissor[0] = scissor[0];
8744 if (skyscissor[1] > scissor[1])
8746 skyscissor[3] += skyscissor[1] - scissor[1];
8747 skyscissor[1] = scissor[1];
8749 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8750 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8751 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8752 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8755 Vector4Copy(scissor, skyscissor);
8760 // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8761 // skymasking on them, and Quake3 never did sky masking (unlike
8762 // software Quake and software Quake2), so disable the sky masking
8763 // in Quake3 maps as it causes problems with q3map2 sky tricks,
8764 // and skymasking also looks very bad when noclipping outside the
8765 // level, so don't use it then either.
8766 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)
8768 R_Mesh_ResetTextureState();
8769 if (skyrendermasked)
8771 R_SetupShader_DepthOrShadow(false, false, false);
8772 // depth-only (masking)
8773 GL_ColorMask(0, 0, 0, 0);
8774 // just to make sure that braindead drivers don't draw
8775 // anything despite that colormask...
8776 GL_BlendFunc(GL_ZERO, GL_ONE);
8777 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8778 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8782 R_SetupShader_Generic_NoTexture(false, false);
8784 GL_BlendFunc(GL_ONE, GL_ZERO);
8785 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8786 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8787 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8790 if (skyrendermasked)
8791 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8793 R_Mesh_ResetTextureState();
8794 GL_Color(1, 1, 1, 1);
8797 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8798 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8799 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
8801 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8805 // render screenspace normalmap to texture
8807 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8812 // bind lightmap texture
8814 // water/refraction/reflection/camera surfaces have to be handled specially
8815 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8817 int start, end, startplaneindex;
8818 for (start = 0;start < texturenumsurfaces;start = end)
8820 startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8821 if(startplaneindex < 0)
8823 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8824 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8828 for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8830 // now that we have a batch using the same planeindex, render it
8831 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8833 // render water or distortion background
8835 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8837 // blend surface on top
8838 GL_DepthMask(false);
8839 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8842 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8844 // render surface with reflection texture as input
8845 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8846 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8853 // render surface batch normally
8854 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8855 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
8859 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8863 int texturesurfaceindex;
8865 const msurface_t *surface;
8866 float surfacecolor4f[4];
8868 // R_Mesh_ResetTextureState();
8869 R_SetupShader_Generic_NoTexture(false, false);
8871 GL_BlendFunc(GL_ONE, GL_ZERO);
8872 GL_DepthMask(writedepth);
8874 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8876 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8878 surface = texturesurfacelist[texturesurfaceindex];
8879 k = (int)(((size_t)surface) / sizeof(msurface_t));
8880 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8881 for (j = 0;j < surface->num_vertices;j++)
8883 Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8887 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8891 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
8894 RSurf_SetupDepthAndCulling();
8895 if (r_showsurfaces.integer && r_refdef.view.showdebug)
8897 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8900 switch (vid.renderpath)
8902 case RENDERPATH_GL32:
8903 case RENDERPATH_GLES2:
8904 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
8910 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8913 int texturenumsurfaces, endsurface;
8915 const msurface_t *surface;
8916 const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8918 RSurf_ActiveModelEntity(ent, true, true, false);
8920 if (r_transparentdepthmasking.integer)
8922 qboolean setup = false;
8923 for (i = 0;i < numsurfaces;i = j)
8926 surface = rsurface.modelsurfaces + surfacelist[i];
8927 texture = surface->texture;
8928 rsurface.texture = R_GetCurrentTexture(texture);
8929 rsurface.lightmaptexture = NULL;
8930 rsurface.deluxemaptexture = NULL;
8931 rsurface.uselightmaptexture = false;
8932 // scan ahead until we find a different texture
8933 endsurface = min(i + 1024, numsurfaces);
8934 texturenumsurfaces = 0;
8935 texturesurfacelist[texturenumsurfaces++] = surface;
8936 for (;j < endsurface;j++)
8938 surface = rsurface.modelsurfaces + surfacelist[j];
8939 if (texture != surface->texture)
8941 texturesurfacelist[texturenumsurfaces++] = surface;
8943 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8945 // render the range of surfaces as depth
8949 GL_ColorMask(0,0,0,0);
8952 GL_BlendFunc(GL_ONE, GL_ZERO);
8954 // R_Mesh_ResetTextureState();
8956 RSurf_SetupDepthAndCulling();
8957 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8958 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8959 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8963 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8966 for (i = 0;i < numsurfaces;i = j)
8969 surface = rsurface.modelsurfaces + surfacelist[i];
8970 texture = surface->texture;
8971 rsurface.texture = R_GetCurrentTexture(texture);
8972 // scan ahead until we find a different texture
8973 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8974 texturenumsurfaces = 0;
8975 texturesurfacelist[texturenumsurfaces++] = surface;
8976 if(FAKELIGHT_ENABLED)
8978 rsurface.lightmaptexture = NULL;
8979 rsurface.deluxemaptexture = NULL;
8980 rsurface.uselightmaptexture = false;
8981 for (;j < endsurface;j++)
8983 surface = rsurface.modelsurfaces + surfacelist[j];
8984 if (texture != surface->texture)
8986 texturesurfacelist[texturenumsurfaces++] = surface;
8991 rsurface.lightmaptexture = surface->lightmaptexture;
8992 rsurface.deluxemaptexture = surface->deluxemaptexture;
8993 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8994 for (;j < endsurface;j++)
8996 surface = rsurface.modelsurfaces + surfacelist[j];
8997 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8999 texturesurfacelist[texturenumsurfaces++] = surface;
9002 // render the range of surfaces
9003 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9005 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9008 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9010 // transparent surfaces get pushed off into the transparent queue
9011 int surfacelistindex;
9012 const msurface_t *surface;
9013 vec3_t tempcenter, center;
9014 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9016 surface = texturesurfacelist[surfacelistindex];
9017 if (r_transparent_sortsurfacesbynearest.integer)
9019 tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9020 tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9021 tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9025 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9026 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9027 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9029 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9030 if (rsurface.entity->transparent_offset) // transparent offset
9032 center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9033 center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9034 center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9036 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);
9040 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9042 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9044 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9046 RSurf_SetupDepthAndCulling();
9047 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9048 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9049 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9053 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9057 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9059 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9062 if (!rsurface.texture->currentnumlayers)
9064 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9065 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9067 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9069 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9070 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9071 else if (!rsurface.texture->currentnumlayers)
9073 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9075 // in the deferred case, transparent surfaces were queued during prepass
9076 if (!r_shadow_usingdeferredprepass)
9077 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9081 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9082 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9087 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9091 R_FrameData_SetMark();
9092 // break the surface list down into batches by texture and use of lightmapping
9093 for (i = 0;i < numsurfaces;i = j)
9096 // texture is the base texture pointer, rsurface.texture is the
9097 // current frame/skin the texture is directing us to use (for example
9098 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9099 // use skin 1 instead)
9100 texture = surfacelist[i]->texture;
9101 rsurface.texture = R_GetCurrentTexture(texture);
9102 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9104 // if this texture is not the kind we want, skip ahead to the next one
9105 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9109 if(FAKELIGHT_ENABLED || depthonly || prepass)
9111 rsurface.lightmaptexture = NULL;
9112 rsurface.deluxemaptexture = NULL;
9113 rsurface.uselightmaptexture = false;
9114 // simply scan ahead until we find a different texture or lightmap state
9115 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9120 rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9121 rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9122 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9123 // simply scan ahead until we find a different texture or lightmap state
9124 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9127 // render the range of surfaces
9128 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9130 R_FrameData_ReturnToMark();
9133 float locboxvertex3f[6*4*3] =
9135 1,0,1, 1,0,0, 1,1,0, 1,1,1,
9136 0,1,1, 0,1,0, 0,0,0, 0,0,1,
9137 1,1,1, 1,1,0, 0,1,0, 0,1,1,
9138 0,0,1, 0,0,0, 1,0,0, 1,0,1,
9139 0,0,1, 1,0,1, 1,1,1, 0,1,1,
9140 1,0,0, 0,0,0, 0,1,0, 1,1,0
9143 unsigned short locboxelements[6*2*3] =
9153 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9156 cl_locnode_t *loc = (cl_locnode_t *)ent;
9158 float vertex3f[6*4*3];
9160 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9161 GL_DepthMask(false);
9162 GL_DepthRange(0, 1);
9163 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9165 GL_CullFace(GL_NONE);
9166 R_EntityMatrix(&identitymatrix);
9168 // R_Mesh_ResetTextureState();
9171 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9172 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9173 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9174 surfacelist[0] < 0 ? 0.5f : 0.125f);
9176 if (VectorCompare(loc->mins, loc->maxs))
9178 VectorSet(size, 2, 2, 2);
9179 VectorMA(loc->mins, -0.5f, size, mins);
9183 VectorCopy(loc->mins, mins);
9184 VectorSubtract(loc->maxs, loc->mins, size);
9187 for (i = 0;i < 6*4*3;)
9188 for (j = 0;j < 3;j++, i++)
9189 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9191 R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9192 R_SetupShader_Generic_NoTexture(false, false);
9193 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9196 void R_DrawLocs(void)
9199 cl_locnode_t *loc, *nearestloc;
9201 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9202 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9204 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9205 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9209 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9211 if (decalsystem->decals)
9212 Mem_Free(decalsystem->decals);
9213 memset(decalsystem, 0, sizeof(*decalsystem));
9216 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)
9222 // expand or initialize the system
9223 if (decalsystem->maxdecals <= decalsystem->numdecals)
9225 decalsystem_t old = *decalsystem;
9226 qboolean useshortelements;
9227 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9228 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9229 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)));
9230 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9231 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9232 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9233 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9234 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9235 if (decalsystem->numdecals)
9236 memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9238 Mem_Free(old.decals);
9239 for (i = 0;i < decalsystem->maxdecals*3;i++)
9240 decalsystem->element3i[i] = i;
9241 if (useshortelements)
9242 for (i = 0;i < decalsystem->maxdecals*3;i++)
9243 decalsystem->element3s[i] = i;
9246 // grab a decal and search for another free slot for the next one
9247 decals = decalsystem->decals;
9248 decal = decalsystem->decals + (i = decalsystem->freedecal++);
9249 for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9251 decalsystem->freedecal = i;
9252 if (decalsystem->numdecals <= i)
9253 decalsystem->numdecals = i + 1;
9255 // initialize the decal
9257 decal->triangleindex = triangleindex;
9258 decal->surfaceindex = surfaceindex;
9259 decal->decalsequence = decalsequence;
9260 decal->color4f[0][0] = c0[0];
9261 decal->color4f[0][1] = c0[1];
9262 decal->color4f[0][2] = c0[2];
9263 decal->color4f[0][3] = 1;
9264 decal->color4f[1][0] = c1[0];
9265 decal->color4f[1][1] = c1[1];
9266 decal->color4f[1][2] = c1[2];
9267 decal->color4f[1][3] = 1;
9268 decal->color4f[2][0] = c2[0];
9269 decal->color4f[2][1] = c2[1];
9270 decal->color4f[2][2] = c2[2];
9271 decal->color4f[2][3] = 1;
9272 decal->vertex3f[0][0] = v0[0];
9273 decal->vertex3f[0][1] = v0[1];
9274 decal->vertex3f[0][2] = v0[2];
9275 decal->vertex3f[1][0] = v1[0];
9276 decal->vertex3f[1][1] = v1[1];
9277 decal->vertex3f[1][2] = v1[2];
9278 decal->vertex3f[2][0] = v2[0];
9279 decal->vertex3f[2][1] = v2[1];
9280 decal->vertex3f[2][2] = v2[2];
9281 decal->texcoord2f[0][0] = t0[0];
9282 decal->texcoord2f[0][1] = t0[1];
9283 decal->texcoord2f[1][0] = t1[0];
9284 decal->texcoord2f[1][1] = t1[1];
9285 decal->texcoord2f[2][0] = t2[0];
9286 decal->texcoord2f[2][1] = t2[1];
9287 TriangleNormal(v0, v1, v2, decal->plane);
9288 VectorNormalize(decal->plane);
9289 decal->plane[3] = DotProduct(v0, decal->plane);
9292 extern cvar_t cl_decals_bias;
9293 extern cvar_t cl_decals_models;
9294 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9295 // baseparms, parms, temps
9296 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)
9301 const float *vertex3f;
9302 const float *normal3f;
9304 float points[2][9][3];
9311 e = rsurface.modelelement3i + 3*triangleindex;
9313 vertex3f = rsurface.modelvertex3f;
9314 normal3f = rsurface.modelnormal3f;
9318 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9320 index = 3*e[cornerindex];
9321 VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9326 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9328 index = 3*e[cornerindex];
9329 VectorCopy(vertex3f + index, v[cornerindex]);
9334 //TriangleNormal(v[0], v[1], v[2], normal);
9335 //if (DotProduct(normal, localnormal) < 0.0f)
9337 // clip by each of the box planes formed from the projection matrix
9338 // if anything survives, we emit the decal
9339 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]);
9342 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]);
9345 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]);
9348 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]);
9351 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]);
9354 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]);
9357 // some part of the triangle survived, so we have to accept it...
9360 // dynamic always uses the original triangle
9362 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9364 index = 3*e[cornerindex];
9365 VectorCopy(vertex3f + index, v[cornerindex]);
9368 for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9370 // convert vertex positions to texcoords
9371 Matrix4x4_Transform(projection, v[cornerindex], temp);
9372 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9373 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9374 // calculate distance fade from the projection origin
9375 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9376 f = bound(0.0f, f, 1.0f);
9377 c[cornerindex][0] = r * f;
9378 c[cornerindex][1] = g * f;
9379 c[cornerindex][2] = b * f;
9380 c[cornerindex][3] = 1.0f;
9381 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9384 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);
9386 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9387 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);
9389 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)
9391 matrix4x4_t projection;
9392 decalsystem_t *decalsystem;
9395 const msurface_t *surface;
9396 const msurface_t *surfaces;
9397 const int *surfacelist;
9398 const texture_t *texture;
9401 int surfacelistindex;
9404 float localorigin[3];
9405 float localnormal[3];
9413 int bih_triangles_count;
9414 int bih_triangles[256];
9415 int bih_surfaces[256];
9417 decalsystem = &ent->decalsystem;
9419 if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9421 R_DecalSystem_Reset(&ent->decalsystem);
9425 if (!model->brush.data_leafs && !cl_decals_models.integer)
9427 if (decalsystem->model)
9428 R_DecalSystem_Reset(decalsystem);
9432 if (decalsystem->model != model)
9433 R_DecalSystem_Reset(decalsystem);
9434 decalsystem->model = model;
9436 RSurf_ActiveModelEntity(ent, true, false, false);
9438 Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9439 Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9440 VectorNormalize(localnormal);
9441 localsize = worldsize*rsurface.inversematrixscale;
9442 localmins[0] = localorigin[0] - localsize;
9443 localmins[1] = localorigin[1] - localsize;
9444 localmins[2] = localorigin[2] - localsize;
9445 localmaxs[0] = localorigin[0] + localsize;
9446 localmaxs[1] = localorigin[1] + localsize;
9447 localmaxs[2] = localorigin[2] + localsize;
9449 //VectorCopy(localnormal, planes[4]);
9450 //VectorVectors(planes[4], planes[2], planes[0]);
9451 AnglesFromVectors(angles, localnormal, NULL, false);
9452 AngleVectors(angles, planes[0], planes[2], planes[4]);
9453 VectorNegate(planes[0], planes[1]);
9454 VectorNegate(planes[2], planes[3]);
9455 VectorNegate(planes[4], planes[5]);
9456 planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9457 planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9458 planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9459 planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9460 planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9461 planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9466 matrix4x4_t forwardprojection;
9467 Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9468 Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9473 float projectionvector[4][3];
9474 VectorScale(planes[0], ilocalsize, projectionvector[0]);
9475 VectorScale(planes[2], ilocalsize, projectionvector[1]);
9476 VectorScale(planes[4], ilocalsize, projectionvector[2]);
9477 projectionvector[0][0] = planes[0][0] * ilocalsize;
9478 projectionvector[0][1] = planes[1][0] * ilocalsize;
9479 projectionvector[0][2] = planes[2][0] * ilocalsize;
9480 projectionvector[1][0] = planes[0][1] * ilocalsize;
9481 projectionvector[1][1] = planes[1][1] * ilocalsize;
9482 projectionvector[1][2] = planes[2][1] * ilocalsize;
9483 projectionvector[2][0] = planes[0][2] * ilocalsize;
9484 projectionvector[2][1] = planes[1][2] * ilocalsize;
9485 projectionvector[2][2] = planes[2][2] * ilocalsize;
9486 projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9487 projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9488 projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9489 Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9493 dynamic = model->surfmesh.isanimated;
9494 numsurfacelist = model->nummodelsurfaces;
9495 surfacelist = model->sortedmodelsurfaces;
9496 surfaces = model->data_surfaces;
9499 bih_triangles_count = -1;
9502 if(model->render_bih.numleafs)
9503 bih = &model->render_bih;
9504 else if(model->collision_bih.numleafs)
9505 bih = &model->collision_bih;
9508 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9509 if(bih_triangles_count == 0)
9511 if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9513 if(bih_triangles_count > 0)
9515 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9517 surfaceindex = bih_surfaces[triangleindex];
9518 surface = surfaces + surfaceindex;
9519 texture = surface->texture;
9520 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9522 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9524 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9529 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9531 surfaceindex = surfacelist[surfacelistindex];
9532 surface = surfaces + surfaceindex;
9533 // check cull box first because it rejects more than any other check
9534 if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9536 // skip transparent surfaces
9537 texture = surface->texture;
9538 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9540 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9542 numtriangles = surface->num_triangles;
9543 for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9544 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9549 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9550 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)
9552 int renderentityindex;
9555 entity_render_t *ent;
9557 if (!cl_decals_newsystem.integer)
9560 worldmins[0] = worldorigin[0] - worldsize;
9561 worldmins[1] = worldorigin[1] - worldsize;
9562 worldmins[2] = worldorigin[2] - worldsize;
9563 worldmaxs[0] = worldorigin[0] + worldsize;
9564 worldmaxs[1] = worldorigin[1] + worldsize;
9565 worldmaxs[2] = worldorigin[2] + worldsize;
9567 R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9569 for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9571 ent = r_refdef.scene.entities[renderentityindex];
9572 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9575 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9579 typedef struct r_decalsystem_splatqueue_s
9586 unsigned int decalsequence;
9588 r_decalsystem_splatqueue_t;
9590 int r_decalsystem_numqueued = 0;
9591 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9593 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)
9595 r_decalsystem_splatqueue_t *queue;
9597 if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9600 queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9601 VectorCopy(worldorigin, queue->worldorigin);
9602 VectorCopy(worldnormal, queue->worldnormal);
9603 Vector4Set(queue->color, r, g, b, a);
9604 Vector4Set(queue->tcrange, s1, t1, s2, t2);
9605 queue->worldsize = worldsize;
9606 queue->decalsequence = cl.decalsequence++;
9609 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9612 r_decalsystem_splatqueue_t *queue;
9614 for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9615 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);
9616 r_decalsystem_numqueued = 0;
9619 extern cvar_t cl_decals_max;
9620 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9623 decalsystem_t *decalsystem = &ent->decalsystem;
9625 unsigned int killsequence;
9630 if (!decalsystem->numdecals)
9633 if (r_showsurfaces.integer)
9636 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9638 R_DecalSystem_Reset(decalsystem);
9642 killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9643 lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9645 if (decalsystem->lastupdatetime)
9646 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9649 decalsystem->lastupdatetime = r_refdef.scene.time;
9650 numdecals = decalsystem->numdecals;
9652 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9654 if (decal->color4f[0][3])
9656 decal->lived += frametime;
9657 if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9659 memset(decal, 0, sizeof(*decal));
9660 if (decalsystem->freedecal > i)
9661 decalsystem->freedecal = i;
9665 decal = decalsystem->decals;
9666 while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9669 // collapse the array by shuffling the tail decals into the gaps
9672 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9673 decalsystem->freedecal++;
9674 if (decalsystem->freedecal == numdecals)
9676 decal[decalsystem->freedecal] = decal[--numdecals];
9679 decalsystem->numdecals = numdecals;
9683 // if there are no decals left, reset decalsystem
9684 R_DecalSystem_Reset(decalsystem);
9688 extern skinframe_t *decalskinframe;
9689 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9692 decalsystem_t *decalsystem = &ent->decalsystem;
9701 const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9704 numdecals = decalsystem->numdecals;
9708 if (r_showsurfaces.integer)
9711 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9713 R_DecalSystem_Reset(decalsystem);
9717 // if the model is static it doesn't matter what value we give for
9718 // wantnormals and wanttangents, so this logic uses only rules applicable
9719 // to a model, knowing that they are meaningless otherwise
9720 RSurf_ActiveModelEntity(ent, false, false, false);
9722 decalsystem->lastupdatetime = r_refdef.scene.time;
9724 faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9726 // update vertex positions for animated models
9727 v3f = decalsystem->vertex3f;
9728 c4f = decalsystem->color4f;
9729 t2f = decalsystem->texcoord2f;
9730 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9732 if (!decal->color4f[0][3])
9735 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9739 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9742 // update color values for fading decals
9743 if (decal->lived >= cl_decals_time.value)
9744 alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9748 c4f[ 0] = decal->color4f[0][0] * alpha;
9749 c4f[ 1] = decal->color4f[0][1] * alpha;
9750 c4f[ 2] = decal->color4f[0][2] * alpha;
9752 c4f[ 4] = decal->color4f[1][0] * alpha;
9753 c4f[ 5] = decal->color4f[1][1] * alpha;
9754 c4f[ 6] = decal->color4f[1][2] * alpha;
9756 c4f[ 8] = decal->color4f[2][0] * alpha;
9757 c4f[ 9] = decal->color4f[2][1] * alpha;
9758 c4f[10] = decal->color4f[2][2] * alpha;
9761 t2f[0] = decal->texcoord2f[0][0];
9762 t2f[1] = decal->texcoord2f[0][1];
9763 t2f[2] = decal->texcoord2f[1][0];
9764 t2f[3] = decal->texcoord2f[1][1];
9765 t2f[4] = decal->texcoord2f[2][0];
9766 t2f[5] = decal->texcoord2f[2][1];
9768 // update vertex positions for animated models
9769 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9771 e = rsurface.modelelement3i + 3*decal->triangleindex;
9772 VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9773 VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9774 VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9778 VectorCopy(decal->vertex3f[0], v3f);
9779 VectorCopy(decal->vertex3f[1], v3f + 3);
9780 VectorCopy(decal->vertex3f[2], v3f + 6);
9783 if (r_refdef.fogenabled)
9785 alpha = RSurf_FogVertex(v3f);
9786 VectorScale(c4f, alpha, c4f);
9787 alpha = RSurf_FogVertex(v3f + 3);
9788 VectorScale(c4f + 4, alpha, c4f + 4);
9789 alpha = RSurf_FogVertex(v3f + 6);
9790 VectorScale(c4f + 8, alpha, c4f + 8);
9801 r_refdef.stats[r_stat_drawndecals] += numtris;
9803 // now render the decals all at once
9804 // (this assumes they all use one particle font texture!)
9805 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);
9806 // R_Mesh_ResetTextureState();
9807 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9808 GL_DepthMask(false);
9809 GL_DepthRange(0, 1);
9810 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9812 GL_CullFace(GL_NONE);
9813 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9814 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9815 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9819 static void R_DrawModelDecals(void)
9823 // fade faster when there are too many decals
9824 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9825 for (i = 0;i < r_refdef.scene.numentities;i++)
9826 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9828 R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9829 for (i = 0;i < r_refdef.scene.numentities;i++)
9830 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9831 R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9833 R_DecalSystem_ApplySplatEntitiesQueue();
9835 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9836 for (i = 0;i < r_refdef.scene.numentities;i++)
9837 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9839 r_refdef.stats[r_stat_totaldecals] += numdecals;
9841 if (r_showsurfaces.integer)
9844 R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9846 for (i = 0;i < r_refdef.scene.numentities;i++)
9848 if (!r_refdef.viewcache.entityvisible[i])
9850 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9851 R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9855 extern cvar_t mod_collision_bih;
9856 static void R_DrawDebugModel(void)
9858 entity_render_t *ent = rsurface.entity;
9859 int i, j, flagsmask;
9860 const msurface_t *surface;
9861 dp_model_t *model = ent->model;
9863 if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9866 if (r_showoverdraw.value > 0)
9868 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9869 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9870 R_SetupShader_Generic_NoTexture(false, false);
9871 GL_DepthTest(false);
9872 GL_DepthMask(false);
9873 GL_DepthRange(0, 1);
9874 GL_BlendFunc(GL_ONE, GL_ONE);
9875 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9877 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9879 rsurface.texture = R_GetCurrentTexture(surface->texture);
9880 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9882 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9883 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9884 if (!rsurface.texture->currentlayers->depthmask)
9885 GL_Color(c, 0, 0, 1.0f);
9886 else if (ent == r_refdef.scene.worldentity)
9887 GL_Color(c, c, c, 1.0f);
9889 GL_Color(0, c, 0, 1.0f);
9890 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9894 rsurface.texture = NULL;
9897 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9899 // R_Mesh_ResetTextureState();
9900 R_SetupShader_Generic_NoTexture(false, false);
9901 GL_DepthRange(0, 1);
9902 GL_DepthTest(!r_showdisabledepthtest.integer);
9903 GL_DepthMask(false);
9904 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9906 if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9910 qboolean cullbox = false;
9911 const q3mbrush_t *brush;
9912 const bih_t *bih = &model->collision_bih;
9913 const bih_leaf_t *bihleaf;
9914 float vertex3f[3][3];
9915 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9916 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9918 if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9920 switch (bihleaf->type)
9923 brush = model->brush.data_brushes + bihleaf->itemindex;
9924 if (brush->colbrushf && brush->colbrushf->numtriangles)
9926 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);
9927 R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9928 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9931 case BIH_COLLISIONTRIANGLE:
9932 triangleindex = bihleaf->itemindex;
9933 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9934 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9935 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9936 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);
9937 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9938 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9940 case BIH_RENDERTRIANGLE:
9941 triangleindex = bihleaf->itemindex;
9942 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9943 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9944 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9945 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);
9946 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9947 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9953 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9956 if (r_showtris.value > 0 && qglPolygonMode)
9958 if (r_showdisabledepthtest.integer)
9960 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9961 GL_DepthMask(false);
9965 GL_BlendFunc(GL_ONE, GL_ZERO);
9968 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9969 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9971 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9973 rsurface.texture = R_GetCurrentTexture(surface->texture);
9974 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9976 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9977 if (!rsurface.texture->currentlayers->depthmask)
9978 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9979 else if (ent == r_refdef.scene.worldentity)
9980 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9982 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9983 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9987 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9988 rsurface.texture = NULL;
9992 // FIXME! implement r_shownormals with just triangles
9993 if (r_shownormals.value != 0 && qglBegin)
9997 if (r_showdisabledepthtest.integer)
9999 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10000 GL_DepthMask(false);
10004 GL_BlendFunc(GL_ONE, GL_ZERO);
10005 GL_DepthMask(true);
10007 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10009 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10011 rsurface.texture = R_GetCurrentTexture(surface->texture);
10012 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10014 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10015 qglBegin(GL_LINES);
10016 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10018 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10020 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10021 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10022 qglVertex3f(v[0], v[1], v[2]);
10023 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10024 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10025 qglVertex3f(v[0], v[1], v[2]);
10028 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10030 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10032 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10033 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10034 qglVertex3f(v[0], v[1], v[2]);
10035 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10036 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10037 qglVertex3f(v[0], v[1], v[2]);
10040 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10042 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10044 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10045 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10046 qglVertex3f(v[0], v[1], v[2]);
10047 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10048 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10049 qglVertex3f(v[0], v[1], v[2]);
10052 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10054 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10056 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10057 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10058 qglVertex3f(v[0], v[1], v[2]);
10059 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10060 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10061 qglVertex3f(v[0], v[1], v[2]);
10068 rsurface.texture = NULL;
10074 int r_maxsurfacelist = 0;
10075 const msurface_t **r_surfacelist = NULL;
10076 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10078 int i, j, endj, flagsmask;
10079 dp_model_t *model = ent->model;
10080 msurface_t *surfaces;
10081 unsigned char *update;
10082 int numsurfacelist = 0;
10086 if (r_maxsurfacelist < model->num_surfaces)
10088 r_maxsurfacelist = model->num_surfaces;
10090 Mem_Free((msurface_t **)r_surfacelist);
10091 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10094 if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10095 RSurf_ActiveModelEntity(ent, false, false, false);
10097 RSurf_ActiveModelEntity(ent, true, true, true);
10098 else if (depthonly)
10099 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10101 RSurf_ActiveModelEntity(ent, true, true, false);
10103 surfaces = model->data_surfaces;
10104 update = model->brushq1.lightmapupdateflags;
10106 // update light styles
10107 if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10109 model_brush_lightstyleinfo_t *style;
10110 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10112 if (style->value != r_refdef.scene.lightstylevalue[style->style])
10114 int *list = style->surfacelist;
10115 style->value = r_refdef.scene.lightstylevalue[style->style];
10116 for (j = 0;j < style->numsurfaces;j++)
10117 update[list[j]] = true;
10122 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10126 R_DrawDebugModel();
10127 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10131 rsurface.lightmaptexture = NULL;
10132 rsurface.deluxemaptexture = NULL;
10133 rsurface.uselightmaptexture = false;
10134 rsurface.texture = NULL;
10135 rsurface.rtlight = NULL;
10136 numsurfacelist = 0;
10137 // add visible surfaces to draw list
10138 if (ent == r_refdef.scene.worldentity)
10140 // for the world entity, check surfacevisible
10141 for (i = 0;i < model->nummodelsurfaces;i++)
10143 j = model->sortedmodelsurfaces[i];
10144 if (r_refdef.viewcache.world_surfacevisible[j])
10145 r_surfacelist[numsurfacelist++] = surfaces + j;
10150 // for ui we have to preserve the order of surfaces
10151 for (i = 0; i < model->nummodelsurfaces; i++)
10152 r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10156 // add all surfaces
10157 for (i = 0; i < model->nummodelsurfaces; i++)
10158 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10160 // don't do anything if there were no surfaces
10161 if (!numsurfacelist)
10163 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10166 // update lightmaps if needed
10170 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10175 R_BuildLightMap(ent, surfaces + j);
10180 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10182 // add to stats if desired
10183 if (r_speeds.integer && !skysurfaces && !depthonly)
10185 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10186 for (j = 0;j < numsurfacelist;j++)
10187 r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10190 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10193 void R_DebugLine(vec3_t start, vec3_t end)
10195 dp_model_t *mod = CL_Mesh_UI();
10197 int e0, e1, e2, e3;
10198 float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10199 float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10200 float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10203 // transform to screen coords first
10204 Vector4Set(w[0], start[0], start[1], start[2], 1);
10205 Vector4Set(w[1], end[0], end[1], end[2], 1);
10206 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10207 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10208 x1 = s[0][0] * vid_conwidth.value / vid.width;
10209 y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10210 x2 = s[1][0] * vid_conwidth.value / vid.width;
10211 y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10212 //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10214 // add the line to the UI mesh for drawing later
10216 // width is measured in real pixels
10217 if (fabs(x2 - x1) > fabs(y2 - y1))
10220 offsety = 0.5f * width * vid_conheight.value / vid.height;
10224 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10227 surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
10228 e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10229 e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10230 e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10231 e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10232 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10233 Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10238 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10241 static texture_t texture;
10242 static msurface_t surface;
10243 const msurface_t *surfacelist = &surface;
10245 // fake enough texture and surface state to render this geometry
10247 texture.update_lastrenderframe = -1; // regenerate this texture
10248 texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10249 texture.basealpha = 1.0f;
10250 texture.currentskinframe = skinframe;
10251 texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10252 texture.offsetmapping = OFFSETMAPPING_OFF;
10253 texture.offsetscale = 1;
10254 texture.specularscalemod = 1;
10255 texture.specularpowermod = 1;
10256 texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10257 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10258 // JUST GREP FOR "specularscalemod = 1".
10260 for (q = 0; q < 3; q++)
10262 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10263 texture.render_modellight_lightdir[q] = q == 2;
10264 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10265 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10266 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10267 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10268 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10269 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10270 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10271 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10273 texture.currentalpha = 1.0f;
10275 surface.texture = &texture;
10276 surface.num_triangles = numtriangles;
10277 surface.num_firsttriangle = firsttriangle;
10278 surface.num_vertices = numvertices;
10279 surface.num_firstvertex = firstvertex;
10282 rsurface.texture = R_GetCurrentTexture(surface.texture);
10283 rsurface.lightmaptexture = NULL;
10284 rsurface.deluxemaptexture = NULL;
10285 rsurface.uselightmaptexture = false;
10286 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10289 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)
10291 static msurface_t surface;
10292 const msurface_t *surfacelist = &surface;
10294 // fake enough texture and surface state to render this geometry
10295 surface.texture = texture;
10296 surface.num_triangles = numtriangles;
10297 surface.num_firsttriangle = firsttriangle;
10298 surface.num_vertices = numvertices;
10299 surface.num_firstvertex = firstvertex;
10302 rsurface.texture = R_GetCurrentTexture(surface.texture);
10303 rsurface.lightmaptexture = NULL;
10304 rsurface.deluxemaptexture = NULL;
10305 rsurface.uselightmaptexture = false;
10306 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);