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 qbool r_loadnormalmap;
48 static qbool r_loadgloss;
50 static qbool r_loaddds;
51 static qbool r_savedds;
52 static qbool r_gpuskeletal;
59 cvar_t r_motionblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
72 cvar_t r_depthfirst = {CF_CLIENT | CF_ARCHIVE, "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"};
73 cvar_t r_useinfinitefarclip = {CF_CLIENT | CF_ARCHIVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CF_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CF_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CF_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CF_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CF_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CF_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CF_CLIENT, "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"};
81 cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
84 cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
85 cvar_t r_showsurfaces = {CF_CLIENT, "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)"};
86 cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CF_CLIENT, "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"};
89 cvar_t r_showcollisionbrushes = {CF_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CF_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CF_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CF_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CF_CLIENT, "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"};
94 cvar_t r_showparticleedges = {CF_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CF_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CF_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CF_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CF_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CF_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CF_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CF_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CF_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CF_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CF_CLIENT, "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)"};
105 cvar_t r_cullentities_trace_enlarge = {CF_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CF_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CF_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CF_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CF_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CF_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CF_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CF_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
114 cvar_t r_fullbright_directed = {CF_CLIENT, "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"};
115 cvar_t r_fullbright_directed_ambient = {CF_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CF_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CF_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CF_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
120 cvar_t r_wateralpha = {CF_CLIENT | CF_ARCHIVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CF_CLIENT | CF_ARCHIVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CF_CLIENT | CF_ARCHIVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CF_CLIENT | CF_ARCHIVE, "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."};
124 cvar_t r_shadows_darken = {CF_CLIENT | CF_ARCHIVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CF_CLIENT | CF_ARCHIVE, "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."};
128 cvar_t r_shadows_castfrombmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CF_CLIENT | CF_ARCHIVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CF_CLIENT | CF_ARCHIVE, "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."};
131 cvar_t r_shadows_shadowmapbias = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CF_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CF_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CF_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CF_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CF_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CF_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CF_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CF_CLIENT | CF_ARCHIVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CF_CLIENT | CF_ARCHIVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CF_CLIENT | CF_ARCHIVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CF_CLIENT | CF_ARCHIVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
147 cvar_t gl_fogenable = {CF_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CF_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CF_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CF_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CF_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CF_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CF_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
156 cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "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"};
159 cvar_t r_textureunits = {CF_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CF_CLIENT | CF_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CF_CLIENT | CF_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
163 cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "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"};
164 cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "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"};
165 cvar_t r_rendertarget_debug = {CF_CLIENT, "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)"};
166 cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "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"};
167 cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
174 cvar_t r_glsl_skeletal = {CF_CLIENT | CF_ARCHIVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CF_CLIENT | CF_ARCHIVE, "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)"};
181 cvar_t r_glsl_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CF_CLIENT | CF_ARCHIVE, "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"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CF_CLIENT | CF_ARCHIVE, "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)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CF_CLIENT | CF_ARCHIVE, "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)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CF_CLIENT | CF_ARCHIVE, "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)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CF_CLIENT | CF_ARCHIVE, "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)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
195 cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CF_CLIENT | CF_ARCHIVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CF_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CF_CLIENT | CF_ARCHIVE, "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"};
205 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_nolerp_list = {CF_CLIENT | CF_ARCHIVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
208 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
209 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
211 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
212 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
214 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
215 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
216 cvar_t r_bloom_resolution = {CF_CLIENT | CF_ARCHIVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
217 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
218 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
219 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
221 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
222 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
223 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
224 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
225 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_value = {CF_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
228 cvar_t r_hdr_irisadaptation_fade_up = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
229 cvar_t r_hdr_irisadaptation_fade_down = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
230 cvar_t r_hdr_irisadaptation_radius = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
232 cvar_t r_smoothnormals_areaweighting = {CF_CLIENT, "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"};
234 cvar_t developer_texturelogging = {CF_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
236 cvar_t gl_lightmaps = {CF_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
238 cvar_t r_test = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
240 cvar_t r_batch_multidraw = {CF_CLIENT | CF_ARCHIVE, "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)"};
241 cvar_t r_batch_multidraw_mintriangles = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
242 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
243 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
245 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
246 cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
248 cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "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."};
250 cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
251 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
253 {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
254 {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
255 {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
256 {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
259 cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"};
260 cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"};
261 cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"};
263 extern cvar_t v_glslgamma_2d;
265 extern qbool v_flipped_state;
267 r_framebufferstate_t r_fb;
269 /// shadow volume bsp struct with automatically growing nodes buffer
272 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
274 rtexture_t *r_texture_blanknormalmap;
275 rtexture_t *r_texture_white;
276 rtexture_t *r_texture_grey128;
277 rtexture_t *r_texture_black;
278 rtexture_t *r_texture_notexture;
279 rtexture_t *r_texture_whitecube;
280 rtexture_t *r_texture_normalizationcube;
281 rtexture_t *r_texture_fogattenuation;
282 rtexture_t *r_texture_fogheighttexture;
283 rtexture_t *r_texture_gammaramps;
284 unsigned int r_texture_gammaramps_serial;
285 //rtexture_t *r_texture_fogintensity;
286 rtexture_t *r_texture_reflectcube;
288 // TODO: hash lookups?
289 typedef struct cubemapinfo_s
296 int r_texture_numcubemaps;
297 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
299 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
300 unsigned int r_numqueries;
301 unsigned int r_maxqueries;
303 typedef struct r_qwskincache_s
305 char name[MAX_QPATH];
306 skinframe_t *skinframe;
310 static r_qwskincache_t *r_qwskincache;
311 static int r_qwskincache_size;
313 /// vertex coordinates for a quad that covers the screen exactly
314 extern const float r_screenvertex3f[12];
315 const float r_screenvertex3f[12] =
323 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
326 for (i = 0;i < verts;i++)
337 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
340 for (i = 0;i < verts;i++)
350 // FIXME: move this to client?
353 if (gamemode == GAME_NEHAHRA)
355 Cvar_Set(&cvars_all, "gl_fogenable", "0");
356 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
357 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
358 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
359 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
361 r_refdef.fog_density = 0;
362 r_refdef.fog_red = 0;
363 r_refdef.fog_green = 0;
364 r_refdef.fog_blue = 0;
365 r_refdef.fog_alpha = 1;
366 r_refdef.fog_start = 0;
367 r_refdef.fog_end = 16384;
368 r_refdef.fog_height = 1<<30;
369 r_refdef.fog_fadedepth = 128;
370 memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
373 static void R_BuildBlankTextures(void)
375 unsigned char data[4];
376 data[2] = 128; // normal X
377 data[1] = 128; // normal Y
378 data[0] = 255; // normal Z
379 data[3] = 255; // height
380 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
385 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
390 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
395 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
398 static void R_BuildNoTexture(void)
400 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
403 static void R_BuildWhiteCube(void)
405 unsigned char data[6*1*1*4];
406 memset(data, 255, sizeof(data));
407 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
410 static void R_BuildNormalizationCube(void)
414 vec_t s, t, intensity;
417 data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
418 for (side = 0;side < 6;side++)
420 for (y = 0;y < NORMSIZE;y++)
422 for (x = 0;x < NORMSIZE;x++)
424 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
425 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
460 intensity = 127.0f / sqrt(DotProduct(v, v));
461 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
462 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
463 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
464 data[((side*64+y)*64+x)*4+3] = 255;
468 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
472 static void R_BuildFogTexture(void)
476 unsigned char data1[FOGWIDTH][4];
477 //unsigned char data2[FOGWIDTH][4];
480 r_refdef.fogmasktable_start = r_refdef.fog_start;
481 r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
482 r_refdef.fogmasktable_range = r_refdef.fogrange;
483 r_refdef.fogmasktable_density = r_refdef.fog_density;
485 r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
486 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
488 d = (x * r - r_refdef.fogmasktable_start);
489 if(developer_extra.integer)
490 Con_DPrintf("%f ", d);
492 if (r_fog_exp2.integer)
493 alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
495 alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
496 if(developer_extra.integer)
497 Con_DPrintf(" : %f ", alpha);
498 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
499 if(developer_extra.integer)
500 Con_DPrintf(" = %f\n", alpha);
501 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
504 for (x = 0;x < FOGWIDTH;x++)
506 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
511 //data2[x][0] = 255 - b;
512 //data2[x][1] = 255 - b;
513 //data2[x][2] = 255 - b;
516 if (r_texture_fogattenuation)
518 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
519 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
523 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
524 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
528 static void R_BuildFogHeightTexture(void)
530 unsigned char *inpixels;
538 strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
539 if (r_refdef.fogheighttexturename[0])
540 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
543 r_refdef.fog_height_tablesize = 0;
544 if (r_texture_fogheighttexture)
545 R_FreeTexture(r_texture_fogheighttexture);
546 r_texture_fogheighttexture = NULL;
547 if (r_refdef.fog_height_table2d)
548 Mem_Free(r_refdef.fog_height_table2d);
549 r_refdef.fog_height_table2d = NULL;
550 if (r_refdef.fog_height_table1d)
551 Mem_Free(r_refdef.fog_height_table1d);
552 r_refdef.fog_height_table1d = NULL;
556 r_refdef.fog_height_tablesize = size;
557 r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
558 r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
559 memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
561 // LadyHavoc: now the magic - what is that table2d for? it is a cooked
562 // average fog color table accounting for every fog layer between a point
563 // and the camera. (Note: attenuation is handled separately!)
564 for (y = 0;y < size;y++)
566 for (x = 0;x < size;x++)
572 for (j = x;j <= y;j++)
574 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
580 for (j = x;j >= y;j--)
582 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
587 r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
588 r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
589 r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
590 r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
593 r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
596 //=======================================================================================================================================================
598 static const char *builtinshaderstrings[] =
600 #include "shader_glsl.h"
604 //=======================================================================================================================================================
606 typedef struct shaderpermutationinfo_s
611 shaderpermutationinfo_t;
613 typedef struct shadermodeinfo_s
615 const char *sourcebasename;
616 const char *extension;
617 const char **builtinshaderstrings;
626 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
627 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
629 {"#define USEDIFFUSE\n", " diffuse"},
630 {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
631 {"#define USEVIEWTINT\n", " viewtint"},
632 {"#define USECOLORMAPPING\n", " colormapping"},
633 {"#define USESATURATION\n", " saturation"},
634 {"#define USEFOGINSIDE\n", " foginside"},
635 {"#define USEFOGOUTSIDE\n", " fogoutside"},
636 {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
637 {"#define USEFOGALPHAHACK\n", " fogalphahack"},
638 {"#define USEGAMMARAMPS\n", " gammaramps"},
639 {"#define USECUBEFILTER\n", " cubefilter"},
640 {"#define USEGLOW\n", " glow"},
641 {"#define USEBLOOM\n", " bloom"},
642 {"#define USESPECULAR\n", " specular"},
643 {"#define USEPOSTPROCESSING\n", " postprocessing"},
644 {"#define USEREFLECTION\n", " reflection"},
645 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
646 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
647 {"#define USESHADOWMAP2D\n", " shadowmap2d"},
648 {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
649 {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
650 {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
651 {"#define USEALPHAKILL\n", " alphakill"},
652 {"#define USEREFLECTCUBE\n", " reflectcube"},
653 {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
654 {"#define USEBOUNCEGRID\n", " bouncegrid"},
655 {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
656 {"#define USETRIPPY\n", " trippy"},
657 {"#define USEDEPTHRGB\n", " depthrgb"},
658 {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
659 {"#define USESKELETAL\n", " skeletal"},
660 {"#define USEOCCLUDE\n", " occlude"}
663 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
664 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
666 // SHADERLANGUAGE_GLSL
668 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
669 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
670 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
671 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
672 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
673 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
674 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
675 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
676 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
677 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
678 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
679 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
680 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
681 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
682 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
683 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
684 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
688 struct r_glsl_permutation_s;
689 typedef struct r_glsl_permutation_s
692 struct r_glsl_permutation_s *hashnext;
694 uint64_t permutation;
696 /// indicates if we have tried compiling this permutation already
698 /// 0 if compilation failed
700 // texture units assigned to each detected uniform
701 int tex_Texture_First;
702 int tex_Texture_Second;
703 int tex_Texture_GammaRamps;
704 int tex_Texture_Normal;
705 int tex_Texture_Color;
706 int tex_Texture_Gloss;
707 int tex_Texture_Glow;
708 int tex_Texture_SecondaryNormal;
709 int tex_Texture_SecondaryColor;
710 int tex_Texture_SecondaryGloss;
711 int tex_Texture_SecondaryGlow;
712 int tex_Texture_Pants;
713 int tex_Texture_Shirt;
714 int tex_Texture_FogHeightTexture;
715 int tex_Texture_FogMask;
716 int tex_Texture_LightGrid;
717 int tex_Texture_Lightmap;
718 int tex_Texture_Deluxemap;
719 int tex_Texture_Attenuation;
720 int tex_Texture_Cube;
721 int tex_Texture_Refraction;
722 int tex_Texture_Reflection;
723 int tex_Texture_ShadowMap2D;
724 int tex_Texture_CubeProjection;
725 int tex_Texture_ScreenNormalMap;
726 int tex_Texture_ScreenDiffuse;
727 int tex_Texture_ScreenSpecular;
728 int tex_Texture_ReflectMask;
729 int tex_Texture_ReflectCube;
730 int tex_Texture_BounceGrid;
731 /// locations of detected uniforms in program object, or -1 if not found
732 int loc_Texture_First;
733 int loc_Texture_Second;
734 int loc_Texture_GammaRamps;
735 int loc_Texture_Normal;
736 int loc_Texture_Color;
737 int loc_Texture_Gloss;
738 int loc_Texture_Glow;
739 int loc_Texture_SecondaryNormal;
740 int loc_Texture_SecondaryColor;
741 int loc_Texture_SecondaryGloss;
742 int loc_Texture_SecondaryGlow;
743 int loc_Texture_Pants;
744 int loc_Texture_Shirt;
745 int loc_Texture_FogHeightTexture;
746 int loc_Texture_FogMask;
747 int loc_Texture_LightGrid;
748 int loc_Texture_Lightmap;
749 int loc_Texture_Deluxemap;
750 int loc_Texture_Attenuation;
751 int loc_Texture_Cube;
752 int loc_Texture_Refraction;
753 int loc_Texture_Reflection;
754 int loc_Texture_ShadowMap2D;
755 int loc_Texture_CubeProjection;
756 int loc_Texture_ScreenNormalMap;
757 int loc_Texture_ScreenDiffuse;
758 int loc_Texture_ScreenSpecular;
759 int loc_Texture_ReflectMask;
760 int loc_Texture_ReflectCube;
761 int loc_Texture_BounceGrid;
763 int loc_BloomBlur_Parameters;
765 int loc_Color_Ambient;
766 int loc_Color_Diffuse;
767 int loc_Color_Specular;
771 int loc_DeferredColor_Ambient;
772 int loc_DeferredColor_Diffuse;
773 int loc_DeferredColor_Specular;
774 int loc_DeferredMod_Diffuse;
775 int loc_DeferredMod_Specular;
776 int loc_DistortScaleRefractReflect;
779 int loc_FogHeightFade;
781 int loc_FogPlaneViewDist;
782 int loc_FogRangeRecip;
785 int loc_LightGridMatrix;
786 int loc_LightGridNormalMatrix;
787 int loc_LightPosition;
788 int loc_OffsetMapping_ScaleSteps;
789 int loc_OffsetMapping_LodDistance;
790 int loc_OffsetMapping_Bias;
792 int loc_ReflectColor;
793 int loc_ReflectFactor;
794 int loc_ReflectOffset;
795 int loc_RefractColor;
797 int loc_ScreenCenterRefractReflect;
798 int loc_ScreenScaleRefractReflect;
799 int loc_ScreenToDepth;
800 int loc_ShadowMap_Parameters;
801 int loc_ShadowMap_TextureScale;
802 int loc_SpecularPower;
803 int loc_Skeletal_Transform12;
809 int loc_ViewTintColor;
811 int loc_ModelToLight;
813 int loc_BackgroundTexMatrix;
814 int loc_ModelViewProjectionMatrix;
815 int loc_ModelViewMatrix;
816 int loc_PixelToScreenTexCoord;
817 int loc_ModelToReflectCube;
818 int loc_ShadowMapMatrix;
819 int loc_BloomColorSubtract;
820 int loc_NormalmapScrollBlend;
821 int loc_BounceGridMatrix;
822 int loc_BounceGridIntensity;
823 /// uniform block bindings
824 int ubibind_Skeletal_Transform12_UniformBlock;
825 /// uniform block indices
826 int ubiloc_Skeletal_Transform12_UniformBlock;
828 r_glsl_permutation_t;
830 #define SHADERPERMUTATION_HASHSIZE 256
833 // non-degradable "lightweight" shader parameters to keep the permutations simpler
834 // these can NOT degrade! only use for simple stuff
837 SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
838 SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
839 SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
840 SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
841 SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
842 SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled
843 SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
844 SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping
845 SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
846 SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
847 SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
848 SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
849 SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
850 SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
852 #define SHADERSTATICPARMS_COUNT 14
854 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
855 static int shaderstaticparms_count = 0;
857 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
858 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
860 extern qbool r_shadow_shadowmapsampler;
861 extern int r_shadow_shadowmappcf;
862 qbool R_CompileShader_CheckStaticParms(void)
864 static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
865 memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
866 memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
869 if (r_glsl_saturation_redcompensate.integer)
870 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
871 if (r_glsl_vertextextureblend_usebothalphas.integer)
872 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
873 if (r_shadow_glossexact.integer)
874 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
875 if (r_glsl_postprocess.integer)
877 if (r_glsl_postprocess_uservec1_enable.integer)
878 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
879 if (r_glsl_postprocess_uservec2_enable.integer)
880 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
881 if (r_glsl_postprocess_uservec3_enable.integer)
882 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
883 if (r_glsl_postprocess_uservec4_enable.integer)
884 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
887 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
888 if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
889 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
891 if (r_shadow_shadowmapsampler)
892 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
893 if (r_shadow_shadowmappcf > 1)
894 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
895 else if (r_shadow_shadowmappcf)
896 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
897 if (r_celshading.integer)
898 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
899 if (r_celoutlines.integer)
900 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
902 return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
905 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
906 if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
907 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
909 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
910 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
912 shaderstaticparms_count = 0;
915 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
916 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
917 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
918 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
919 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
920 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
921 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
922 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
923 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
924 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
925 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
926 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
927 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
928 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
931 /// information about each possible shader permutation
932 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
933 /// currently selected permutation
934 r_glsl_permutation_t *r_glsl_permutation;
935 /// storage for permutations linked in the hash table
936 memexpandablearray_t r_glsl_permutationarray;
938 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
940 //unsigned int hashdepth = 0;
941 unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
942 r_glsl_permutation_t *p;
943 for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
945 if (p->mode == mode && p->permutation == permutation)
947 //if (hashdepth > 10)
948 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
953 p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
955 p->permutation = permutation;
956 p->hashnext = r_glsl_permutationhash[mode][hashindex];
957 r_glsl_permutationhash[mode][hashindex] = p;
958 //if (hashdepth > 10)
959 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
963 static char *R_ShaderStrCat(const char **strings)
966 const char **p = strings;
969 for (p = strings;(t = *p);p++)
972 s = string = (char *)Mem_Alloc(r_main_mempool, len);
974 for (p = strings;(t = *p);p++)
984 static char *R_ShaderStrCat(const char **strings);
985 static void R_InitShaderModeInfo(void)
988 shadermodeinfo_t *modeinfo;
989 // 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)
990 for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
992 for (i = 0; i < SHADERMODE_COUNT; i++)
994 char filename[MAX_QPATH];
995 modeinfo = &shadermodeinfo[language][i];
996 modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
997 modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
998 dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
999 modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1004 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1007 // if the mode has no filename we have to return the builtin string
1008 if (builtinonly || !modeinfo->filename)
1009 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1010 // note that FS_LoadFile appends a 0 byte to make it a valid string
1011 shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1014 if (printfromdisknotice)
1015 Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1016 return shaderstring;
1018 // fall back to builtinstring
1019 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1022 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1027 shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1029 char permutationname[256];
1030 int vertstrings_count = 0;
1031 int geomstrings_count = 0;
1032 int fragstrings_count = 0;
1033 const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1034 const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1035 const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1042 permutationname[0] = 0;
1043 sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1045 strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1047 // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1048 if(vid.support.glshaderversion >= 140)
1050 vertstrings_list[vertstrings_count++] = "#version 140\n";
1051 geomstrings_list[geomstrings_count++] = "#version 140\n";
1052 fragstrings_list[fragstrings_count++] = "#version 140\n";
1053 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1054 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1055 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1057 // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1058 else if(vid.support.glshaderversion >= 130)
1060 vertstrings_list[vertstrings_count++] = "#version 130\n";
1061 geomstrings_list[geomstrings_count++] = "#version 130\n";
1062 fragstrings_list[fragstrings_count++] = "#version 130\n";
1063 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1064 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1065 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1067 // if we can do #version 120, we should (this adds the invariant keyword)
1068 else if(vid.support.glshaderversion >= 120)
1070 vertstrings_list[vertstrings_count++] = "#version 120\n";
1071 geomstrings_list[geomstrings_count++] = "#version 120\n";
1072 fragstrings_list[fragstrings_count++] = "#version 120\n";
1073 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1074 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1075 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1077 // GLES also adds several things from GLSL120
1078 switch(vid.renderpath)
1080 case RENDERPATH_GLES2:
1081 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1082 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1083 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1089 // the first pretext is which type of shader to compile as
1090 // (later these will all be bound together as a program object)
1091 vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1092 geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1093 fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1095 // the second pretext is the mode (for example a light source)
1096 vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1097 geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1098 fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1099 strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1101 // now add all the permutation pretexts
1102 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1104 if (permutation & (1ll<<i))
1106 vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1107 geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1108 fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1109 strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1113 // keep line numbers correct
1114 vertstrings_list[vertstrings_count++] = "\n";
1115 geomstrings_list[geomstrings_count++] = "\n";
1116 fragstrings_list[fragstrings_count++] = "\n";
1121 R_CompileShader_AddStaticParms(mode, permutation);
1122 memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1123 vertstrings_count += shaderstaticparms_count;
1124 memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1125 geomstrings_count += shaderstaticparms_count;
1126 memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1127 fragstrings_count += shaderstaticparms_count;
1129 // now append the shader text itself
1130 vertstrings_list[vertstrings_count++] = sourcestring;
1131 geomstrings_list[geomstrings_count++] = sourcestring;
1132 fragstrings_list[fragstrings_count++] = sourcestring;
1134 // we don't currently use geometry shaders for anything, so just empty the list
1135 geomstrings_count = 0;
1137 // compile the shader program
1138 if (vertstrings_count + geomstrings_count + fragstrings_count)
1139 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1143 qglUseProgram(p->program);CHECKGLERROR
1144 // look up all the uniform variable names we care about, so we don't
1145 // have to look them up every time we set them
1150 GLint activeuniformindex = 0;
1151 GLint numactiveuniforms = 0;
1152 char uniformname[128];
1153 GLsizei uniformnamelength = 0;
1154 GLint uniformsize = 0;
1155 GLenum uniformtype = 0;
1156 memset(uniformname, 0, sizeof(uniformname));
1157 qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1158 Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1159 for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1161 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1162 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1167 p->loc_Texture_First = qglGetUniformLocation(p->program, "Texture_First");
1168 p->loc_Texture_Second = qglGetUniformLocation(p->program, "Texture_Second");
1169 p->loc_Texture_GammaRamps = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1170 p->loc_Texture_Normal = qglGetUniformLocation(p->program, "Texture_Normal");
1171 p->loc_Texture_Color = qglGetUniformLocation(p->program, "Texture_Color");
1172 p->loc_Texture_Gloss = qglGetUniformLocation(p->program, "Texture_Gloss");
1173 p->loc_Texture_Glow = qglGetUniformLocation(p->program, "Texture_Glow");
1174 p->loc_Texture_SecondaryNormal = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1175 p->loc_Texture_SecondaryColor = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1176 p->loc_Texture_SecondaryGloss = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1177 p->loc_Texture_SecondaryGlow = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1178 p->loc_Texture_Pants = qglGetUniformLocation(p->program, "Texture_Pants");
1179 p->loc_Texture_Shirt = qglGetUniformLocation(p->program, "Texture_Shirt");
1180 p->loc_Texture_FogHeightTexture = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1181 p->loc_Texture_FogMask = qglGetUniformLocation(p->program, "Texture_FogMask");
1182 p->loc_Texture_LightGrid = qglGetUniformLocation(p->program, "Texture_LightGrid");
1183 p->loc_Texture_Lightmap = qglGetUniformLocation(p->program, "Texture_Lightmap");
1184 p->loc_Texture_Deluxemap = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1185 p->loc_Texture_Attenuation = qglGetUniformLocation(p->program, "Texture_Attenuation");
1186 p->loc_Texture_Cube = qglGetUniformLocation(p->program, "Texture_Cube");
1187 p->loc_Texture_Refraction = qglGetUniformLocation(p->program, "Texture_Refraction");
1188 p->loc_Texture_Reflection = qglGetUniformLocation(p->program, "Texture_Reflection");
1189 p->loc_Texture_ShadowMap2D = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1190 p->loc_Texture_CubeProjection = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1191 p->loc_Texture_ScreenNormalMap = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1192 p->loc_Texture_ScreenDiffuse = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1193 p->loc_Texture_ScreenSpecular = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1194 p->loc_Texture_ReflectMask = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1195 p->loc_Texture_ReflectCube = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1196 p->loc_Texture_BounceGrid = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1197 p->loc_Alpha = qglGetUniformLocation(p->program, "Alpha");
1198 p->loc_BloomBlur_Parameters = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1199 p->loc_ClientTime = qglGetUniformLocation(p->program, "ClientTime");
1200 p->loc_Color_Ambient = qglGetUniformLocation(p->program, "Color_Ambient");
1201 p->loc_Color_Diffuse = qglGetUniformLocation(p->program, "Color_Diffuse");
1202 p->loc_Color_Specular = qglGetUniformLocation(p->program, "Color_Specular");
1203 p->loc_Color_Glow = qglGetUniformLocation(p->program, "Color_Glow");
1204 p->loc_Color_Pants = qglGetUniformLocation(p->program, "Color_Pants");
1205 p->loc_Color_Shirt = qglGetUniformLocation(p->program, "Color_Shirt");
1206 p->loc_DeferredColor_Ambient = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1207 p->loc_DeferredColor_Diffuse = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1208 p->loc_DeferredColor_Specular = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1209 p->loc_DeferredMod_Diffuse = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1210 p->loc_DeferredMod_Specular = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1211 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1212 p->loc_EyePosition = qglGetUniformLocation(p->program, "EyePosition");
1213 p->loc_FogColor = qglGetUniformLocation(p->program, "FogColor");
1214 p->loc_FogHeightFade = qglGetUniformLocation(p->program, "FogHeightFade");
1215 p->loc_FogPlane = qglGetUniformLocation(p->program, "FogPlane");
1216 p->loc_FogPlaneViewDist = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1217 p->loc_FogRangeRecip = qglGetUniformLocation(p->program, "FogRangeRecip");
1218 p->loc_LightColor = qglGetUniformLocation(p->program, "LightColor");
1219 p->loc_LightGridMatrix = qglGetUniformLocation(p->program, "LightGridMatrix");
1220 p->loc_LightGridNormalMatrix = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1221 p->loc_LightDir = qglGetUniformLocation(p->program, "LightDir");
1222 p->loc_LightPosition = qglGetUniformLocation(p->program, "LightPosition");
1223 p->loc_OffsetMapping_ScaleSteps = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1224 p->loc_OffsetMapping_LodDistance = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1225 p->loc_OffsetMapping_Bias = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1226 p->loc_PixelSize = qglGetUniformLocation(p->program, "PixelSize");
1227 p->loc_ReflectColor = qglGetUniformLocation(p->program, "ReflectColor");
1228 p->loc_ReflectFactor = qglGetUniformLocation(p->program, "ReflectFactor");
1229 p->loc_ReflectOffset = qglGetUniformLocation(p->program, "ReflectOffset");
1230 p->loc_RefractColor = qglGetUniformLocation(p->program, "RefractColor");
1231 p->loc_Saturation = qglGetUniformLocation(p->program, "Saturation");
1232 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1233 p->loc_ScreenScaleRefractReflect = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1234 p->loc_ScreenToDepth = qglGetUniformLocation(p->program, "ScreenToDepth");
1235 p->loc_ShadowMap_Parameters = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1236 p->loc_ShadowMap_TextureScale = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1237 p->loc_SpecularPower = qglGetUniformLocation(p->program, "SpecularPower");
1238 p->loc_UserVec1 = qglGetUniformLocation(p->program, "UserVec1");
1239 p->loc_UserVec2 = qglGetUniformLocation(p->program, "UserVec2");
1240 p->loc_UserVec3 = qglGetUniformLocation(p->program, "UserVec3");
1241 p->loc_UserVec4 = qglGetUniformLocation(p->program, "UserVec4");
1242 p->loc_ColorFringe = qglGetUniformLocation(p->program, "ColorFringe");
1243 p->loc_ViewTintColor = qglGetUniformLocation(p->program, "ViewTintColor");
1244 p->loc_ViewToLight = qglGetUniformLocation(p->program, "ViewToLight");
1245 p->loc_ModelToLight = qglGetUniformLocation(p->program, "ModelToLight");
1246 p->loc_TexMatrix = qglGetUniformLocation(p->program, "TexMatrix");
1247 p->loc_BackgroundTexMatrix = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1248 p->loc_ModelViewMatrix = qglGetUniformLocation(p->program, "ModelViewMatrix");
1249 p->loc_ModelViewProjectionMatrix = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1250 p->loc_PixelToScreenTexCoord = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1251 p->loc_ModelToReflectCube = qglGetUniformLocation(p->program, "ModelToReflectCube");
1252 p->loc_ShadowMapMatrix = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1253 p->loc_BloomColorSubtract = qglGetUniformLocation(p->program, "BloomColorSubtract");
1254 p->loc_NormalmapScrollBlend = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1255 p->loc_BounceGridMatrix = qglGetUniformLocation(p->program, "BounceGridMatrix");
1256 p->loc_BounceGridIntensity = qglGetUniformLocation(p->program, "BounceGridIntensity");
1257 // initialize the samplers to refer to the texture units we use
1258 p->tex_Texture_First = -1;
1259 p->tex_Texture_Second = -1;
1260 p->tex_Texture_GammaRamps = -1;
1261 p->tex_Texture_Normal = -1;
1262 p->tex_Texture_Color = -1;
1263 p->tex_Texture_Gloss = -1;
1264 p->tex_Texture_Glow = -1;
1265 p->tex_Texture_SecondaryNormal = -1;
1266 p->tex_Texture_SecondaryColor = -1;
1267 p->tex_Texture_SecondaryGloss = -1;
1268 p->tex_Texture_SecondaryGlow = -1;
1269 p->tex_Texture_Pants = -1;
1270 p->tex_Texture_Shirt = -1;
1271 p->tex_Texture_FogHeightTexture = -1;
1272 p->tex_Texture_FogMask = -1;
1273 p->tex_Texture_LightGrid = -1;
1274 p->tex_Texture_Lightmap = -1;
1275 p->tex_Texture_Deluxemap = -1;
1276 p->tex_Texture_Attenuation = -1;
1277 p->tex_Texture_Cube = -1;
1278 p->tex_Texture_Refraction = -1;
1279 p->tex_Texture_Reflection = -1;
1280 p->tex_Texture_ShadowMap2D = -1;
1281 p->tex_Texture_CubeProjection = -1;
1282 p->tex_Texture_ScreenNormalMap = -1;
1283 p->tex_Texture_ScreenDiffuse = -1;
1284 p->tex_Texture_ScreenSpecular = -1;
1285 p->tex_Texture_ReflectMask = -1;
1286 p->tex_Texture_ReflectCube = -1;
1287 p->tex_Texture_BounceGrid = -1;
1288 // bind the texture samplers in use
1290 if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;}
1291 if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;}
1292 if (p->loc_Texture_GammaRamps >= 0) {p->tex_Texture_GammaRamps = sampler;qglUniform1i(p->loc_Texture_GammaRamps , sampler);sampler++;}
1293 if (p->loc_Texture_Normal >= 0) {p->tex_Texture_Normal = sampler;qglUniform1i(p->loc_Texture_Normal , sampler);sampler++;}
1294 if (p->loc_Texture_Color >= 0) {p->tex_Texture_Color = sampler;qglUniform1i(p->loc_Texture_Color , sampler);sampler++;}
1295 if (p->loc_Texture_Gloss >= 0) {p->tex_Texture_Gloss = sampler;qglUniform1i(p->loc_Texture_Gloss , sampler);sampler++;}
1296 if (p->loc_Texture_Glow >= 0) {p->tex_Texture_Glow = sampler;qglUniform1i(p->loc_Texture_Glow , sampler);sampler++;}
1297 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1298 if (p->loc_Texture_SecondaryColor >= 0) {p->tex_Texture_SecondaryColor = sampler;qglUniform1i(p->loc_Texture_SecondaryColor , sampler);sampler++;}
1299 if (p->loc_Texture_SecondaryGloss >= 0) {p->tex_Texture_SecondaryGloss = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss , sampler);sampler++;}
1300 if (p->loc_Texture_SecondaryGlow >= 0) {p->tex_Texture_SecondaryGlow = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow , sampler);sampler++;}
1301 if (p->loc_Texture_Pants >= 0) {p->tex_Texture_Pants = sampler;qglUniform1i(p->loc_Texture_Pants , sampler);sampler++;}
1302 if (p->loc_Texture_Shirt >= 0) {p->tex_Texture_Shirt = sampler;qglUniform1i(p->loc_Texture_Shirt , sampler);sampler++;}
1303 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1304 if (p->loc_Texture_FogMask >= 0) {p->tex_Texture_FogMask = sampler;qglUniform1i(p->loc_Texture_FogMask , sampler);sampler++;}
1305 if (p->loc_Texture_LightGrid >= 0) {p->tex_Texture_LightGrid = sampler;qglUniform1i(p->loc_Texture_LightGrid , sampler);sampler++;}
1306 if (p->loc_Texture_Lightmap >= 0) {p->tex_Texture_Lightmap = sampler;qglUniform1i(p->loc_Texture_Lightmap , sampler);sampler++;}
1307 if (p->loc_Texture_Deluxemap >= 0) {p->tex_Texture_Deluxemap = sampler;qglUniform1i(p->loc_Texture_Deluxemap , sampler);sampler++;}
1308 if (p->loc_Texture_Attenuation >= 0) {p->tex_Texture_Attenuation = sampler;qglUniform1i(p->loc_Texture_Attenuation , sampler);sampler++;}
1309 if (p->loc_Texture_Cube >= 0) {p->tex_Texture_Cube = sampler;qglUniform1i(p->loc_Texture_Cube , sampler);sampler++;}
1310 if (p->loc_Texture_Refraction >= 0) {p->tex_Texture_Refraction = sampler;qglUniform1i(p->loc_Texture_Refraction , sampler);sampler++;}
1311 if (p->loc_Texture_Reflection >= 0) {p->tex_Texture_Reflection = sampler;qglUniform1i(p->loc_Texture_Reflection , sampler);sampler++;}
1312 if (p->loc_Texture_ShadowMap2D >= 0) {p->tex_Texture_ShadowMap2D = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D , sampler);sampler++;}
1313 if (p->loc_Texture_CubeProjection >= 0) {p->tex_Texture_CubeProjection = sampler;qglUniform1i(p->loc_Texture_CubeProjection , sampler);sampler++;}
1314 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1315 if (p->loc_Texture_ScreenDiffuse >= 0) {p->tex_Texture_ScreenDiffuse = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse , sampler);sampler++;}
1316 if (p->loc_Texture_ScreenSpecular >= 0) {p->tex_Texture_ScreenSpecular = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular , sampler);sampler++;}
1317 if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;}
1318 if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;}
1319 if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;}
1320 // get the uniform block indices so we can bind them
1321 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1322 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1323 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1325 // clear the uniform block bindings
1326 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1327 // bind the uniform blocks in use
1329 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1330 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1332 // we're done compiling and setting up the shader, at least until it is used
1334 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1337 Con_Printf("^1GLSL shader %s failed! some features may not work properly.\n", permutationname);
1341 Mem_Free(sourcestring);
1344 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1346 r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1347 if (r_glsl_permutation != perm)
1349 r_glsl_permutation = perm;
1350 if (!r_glsl_permutation->program)
1352 if (!r_glsl_permutation->compiled)
1354 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1355 R_GLSL_CompilePermutation(perm, mode, permutation);
1357 if (!r_glsl_permutation->program)
1359 // remove features until we find a valid permutation
1361 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1363 // reduce i more quickly whenever it would not remove any bits
1364 uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1365 if (!(permutation & j))
1368 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1369 if (!r_glsl_permutation->compiled)
1370 R_GLSL_CompilePermutation(perm, mode, permutation);
1371 if (r_glsl_permutation->program)
1374 if (i >= SHADERPERMUTATION_COUNT)
1376 //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1377 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1378 qglUseProgram(0);CHECKGLERROR
1379 return; // no bit left to clear, entire mode is broken
1384 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1386 if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1387 if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1388 if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1392 void R_GLSL_Restart_f(cmd_state_t *cmd)
1394 unsigned int i, limit;
1395 switch(vid.renderpath)
1397 case RENDERPATH_GL32:
1398 case RENDERPATH_GLES2:
1400 r_glsl_permutation_t *p;
1401 r_glsl_permutation = NULL;
1402 limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1403 for (i = 0;i < limit;i++)
1405 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1407 GL_Backend_FreeProgram(p->program);
1408 Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1411 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1417 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1419 int i, language, mode, dupe;
1421 shadermodeinfo_t *modeinfo;
1424 for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1426 modeinfo = shadermodeinfo[language];
1427 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1429 // don't dump the same file multiple times (most or all shaders come from the same file)
1430 for (dupe = mode - 1;dupe >= 0;dupe--)
1431 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1435 text = modeinfo[mode].builtinstring;
1438 file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1441 FS_Print(file, "/* The engine may define the following macros:\n");
1442 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1443 for (i = 0;i < SHADERMODE_COUNT;i++)
1444 FS_Print(file, modeinfo[i].pretext);
1445 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1446 FS_Print(file, shaderpermutationinfo[i].pretext);
1447 FS_Print(file, "*/\n");
1448 FS_Print(file, text);
1450 Con_Printf("%s written\n", modeinfo[mode].filename);
1453 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1458 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1460 uint64_t permutation = 0;
1461 if (r_trippy.integer && !notrippy)
1462 permutation |= SHADERPERMUTATION_TRIPPY;
1463 permutation |= SHADERPERMUTATION_VIEWTINT;
1465 permutation |= SHADERPERMUTATION_DIFFUSE;
1466 if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1467 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1468 if (suppresstexalpha)
1469 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1470 if (vid.allowalphatocoverage)
1471 GL_AlphaToCoverage(false);
1472 switch (vid.renderpath)
1474 case RENDERPATH_GL32:
1475 case RENDERPATH_GLES2:
1476 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1477 if (r_glsl_permutation->tex_Texture_First >= 0)
1478 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1479 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1480 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1485 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1487 R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1490 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1492 uint64_t permutation = 0;
1493 if (r_trippy.integer && !notrippy)
1494 permutation |= SHADERPERMUTATION_TRIPPY;
1496 permutation |= SHADERPERMUTATION_DEPTHRGB;
1498 permutation |= SHADERPERMUTATION_SKELETAL;
1500 if (vid.allowalphatocoverage)
1501 GL_AlphaToCoverage(false);
1502 switch (vid.renderpath)
1504 case RENDERPATH_GL32:
1505 case RENDERPATH_GLES2:
1506 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1507 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1508 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);
1514 #define BLENDFUNC_ALLOWS_COLORMOD 1
1515 #define BLENDFUNC_ALLOWS_FOG 2
1516 #define BLENDFUNC_ALLOWS_FOG_HACK0 4
1517 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1518 #define BLENDFUNC_ALLOWS_ANYFOG (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1519 static int R_BlendFuncFlags(int src, int dst)
1523 // a blendfunc allows colormod if:
1524 // a) it can never keep the destination pixel invariant, or
1525 // b) it can keep the destination pixel invariant, and still can do so if colormodded
1526 // this is to prevent unintended side effects from colormod
1528 // a blendfunc allows fog if:
1529 // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1530 // this is to prevent unintended side effects from fog
1532 // these checks are the output of fogeval.pl
1534 r |= BLENDFUNC_ALLOWS_COLORMOD;
1535 if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1536 if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1537 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1538 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1539 if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1540 if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1541 if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1542 if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1543 if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1544 if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1545 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1546 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1547 if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1548 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1549 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1550 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1551 if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1552 if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1553 if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1554 if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1555 if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560 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, qbool notrippy)
1562 // select a permutation of the lighting shader appropriate to this
1563 // combination of texture, entity, light source, and fogging, only use the
1564 // minimum features necessary to avoid wasting rendering time in the
1565 // fragment shader on features that are not being used
1566 uint64_t permutation = 0;
1567 unsigned int mode = 0;
1569 texture_t *t = rsurface.texture;
1571 matrix4x4_t tempmatrix;
1572 r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1573 if (r_trippy.integer && !notrippy)
1574 permutation |= SHADERPERMUTATION_TRIPPY;
1575 if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1576 permutation |= SHADERPERMUTATION_ALPHAKILL;
1577 if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1578 permutation |= SHADERPERMUTATION_OCCLUDE;
1579 if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1580 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1581 if (rsurfacepass == RSURFPASS_BACKGROUND)
1583 // distorted background
1584 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1586 mode = SHADERMODE_WATER;
1587 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1588 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1589 if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1591 // this is the right thing to do for wateralpha
1592 GL_BlendFunc(GL_ONE, GL_ZERO);
1593 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1597 // this is the right thing to do for entity alpha
1598 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1599 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1602 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1604 mode = SHADERMODE_REFRACTION;
1605 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1606 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1607 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1608 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1612 mode = SHADERMODE_GENERIC;
1613 permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1614 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1615 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1617 if (vid.allowalphatocoverage)
1618 GL_AlphaToCoverage(false);
1620 else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1622 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1624 switch(t->offsetmapping)
1626 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1627 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1628 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1629 case OFFSETMAPPING_OFF: break;
1632 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1633 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1634 // normalmap (deferred prepass), may use alpha test on diffuse
1635 mode = SHADERMODE_DEFERREDGEOMETRY;
1636 GL_BlendFunc(GL_ONE, GL_ZERO);
1637 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1638 if (vid.allowalphatocoverage)
1639 GL_AlphaToCoverage(false);
1641 else if (rsurfacepass == RSURFPASS_RTLIGHT)
1643 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1645 switch(t->offsetmapping)
1647 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1648 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1649 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1650 case OFFSETMAPPING_OFF: break;
1653 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1654 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1655 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1656 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1658 mode = SHADERMODE_LIGHTSOURCE;
1659 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1660 permutation |= SHADERPERMUTATION_CUBEFILTER;
1661 if (VectorLength2(rtlightdiffuse) > 0)
1662 permutation |= SHADERPERMUTATION_DIFFUSE;
1663 if (VectorLength2(rtlightspecular) > 0)
1664 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1665 if (r_refdef.fogenabled)
1666 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1667 if (t->colormapping)
1668 permutation |= SHADERPERMUTATION_COLORMAPPING;
1669 if (r_shadow_usingshadowmap2d)
1671 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1672 if(r_shadow_shadowmapvsdct)
1673 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1675 if (r_shadow_shadowmap2ddepthbuffer)
1676 permutation |= SHADERPERMUTATION_DEPTHRGB;
1678 if (t->reflectmasktexture)
1679 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1680 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1681 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1682 if (vid.allowalphatocoverage)
1683 GL_AlphaToCoverage(false);
1685 else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1687 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1689 switch(t->offsetmapping)
1691 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1692 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1693 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1694 case OFFSETMAPPING_OFF: break;
1697 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1698 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1699 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1700 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1701 // directional model lighting
1702 mode = SHADERMODE_LIGHTGRID;
1703 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1704 permutation |= SHADERPERMUTATION_GLOW;
1705 permutation |= SHADERPERMUTATION_DIFFUSE;
1706 if (t->glosstexture || t->backgroundglosstexture)
1707 permutation |= SHADERPERMUTATION_SPECULAR;
1708 if (r_refdef.fogenabled)
1709 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1710 if (t->colormapping)
1711 permutation |= SHADERPERMUTATION_COLORMAPPING;
1712 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1714 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1715 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1717 if (r_shadow_shadowmap2ddepthbuffer)
1718 permutation |= SHADERPERMUTATION_DEPTHRGB;
1720 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1721 permutation |= SHADERPERMUTATION_REFLECTION;
1722 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1723 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1724 if (t->reflectmasktexture)
1725 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1726 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1728 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1729 if (r_shadow_bouncegrid_state.directional)
1730 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1732 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1733 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1734 // when using alphatocoverage, we don't need alphakill
1735 if (vid.allowalphatocoverage)
1737 if (r_transparent_alphatocoverage.integer)
1739 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1740 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1743 GL_AlphaToCoverage(false);
1746 else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1748 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1750 switch(t->offsetmapping)
1752 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1753 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1754 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1755 case OFFSETMAPPING_OFF: break;
1758 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1759 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1760 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1761 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1762 // directional model lighting
1763 mode = SHADERMODE_LIGHTDIRECTION;
1764 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1765 permutation |= SHADERPERMUTATION_GLOW;
1766 if (VectorLength2(t->render_modellight_diffuse))
1767 permutation |= SHADERPERMUTATION_DIFFUSE;
1768 if (VectorLength2(t->render_modellight_specular) > 0)
1769 permutation |= SHADERPERMUTATION_SPECULAR;
1770 if (r_refdef.fogenabled)
1771 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1772 if (t->colormapping)
1773 permutation |= SHADERPERMUTATION_COLORMAPPING;
1774 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1776 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1777 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1779 if (r_shadow_shadowmap2ddepthbuffer)
1780 permutation |= SHADERPERMUTATION_DEPTHRGB;
1782 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1783 permutation |= SHADERPERMUTATION_REFLECTION;
1784 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1785 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1786 if (t->reflectmasktexture)
1787 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1788 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1790 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1791 if (r_shadow_bouncegrid_state.directional)
1792 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1794 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1795 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1796 // when using alphatocoverage, we don't need alphakill
1797 if (vid.allowalphatocoverage)
1799 if (r_transparent_alphatocoverage.integer)
1801 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1802 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1805 GL_AlphaToCoverage(false);
1810 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1812 switch(t->offsetmapping)
1814 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1815 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1816 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1817 case OFFSETMAPPING_OFF: break;
1820 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1821 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1822 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1823 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1825 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1826 permutation |= SHADERPERMUTATION_GLOW;
1827 if (r_refdef.fogenabled && !notrippy)
1828 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1829 if (t->colormapping)
1830 permutation |= SHADERPERMUTATION_COLORMAPPING;
1831 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1833 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1834 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1836 if (r_shadow_shadowmap2ddepthbuffer)
1837 permutation |= SHADERPERMUTATION_DEPTHRGB;
1839 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1840 permutation |= SHADERPERMUTATION_REFLECTION;
1841 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1842 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1843 if (t->reflectmasktexture)
1844 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1845 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1847 // deluxemapping (light direction texture)
1848 if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1849 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1851 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1852 permutation |= SHADERPERMUTATION_DIFFUSE;
1853 if (VectorLength2(t->render_lightmap_specular) > 0)
1854 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1856 else if (r_glsl_deluxemapping.integer >= 2)
1858 // fake deluxemapping (uniform light direction in tangentspace)
1859 if (rsurface.uselightmaptexture)
1860 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1862 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1863 permutation |= SHADERPERMUTATION_DIFFUSE;
1864 if (VectorLength2(t->render_lightmap_specular) > 0)
1865 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1867 else if (rsurface.uselightmaptexture)
1869 // ordinary lightmapping (q1bsp, q3bsp)
1870 mode = SHADERMODE_LIGHTMAP;
1874 // ordinary vertex coloring (q3bsp)
1875 mode = SHADERMODE_VERTEXCOLOR;
1877 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1879 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1880 if (r_shadow_bouncegrid_state.directional)
1881 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1883 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1884 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1885 // when using alphatocoverage, we don't need alphakill
1886 if (vid.allowalphatocoverage)
1888 if (r_transparent_alphatocoverage.integer)
1890 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1891 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1894 GL_AlphaToCoverage(false);
1897 if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1898 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1899 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !notrippy)
1900 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1901 switch(vid.renderpath)
1903 case RENDERPATH_GL32:
1904 case RENDERPATH_GLES2:
1905 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);
1906 RSurf_UploadBuffersForBatch();
1907 // this has to be after RSurf_PrepareVerticesForBatch
1908 if (rsurface.batchskeletaltransform3x4buffer)
1909 permutation |= SHADERPERMUTATION_SKELETAL;
1910 R_SetupShader_SetPermutationGLSL(mode, permutation);
1911 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1912 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);
1914 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1915 if (mode == SHADERMODE_LIGHTSOURCE)
1917 if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1918 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1919 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1920 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1921 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1922 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1924 // additive passes are only darkened by fog, not tinted
1925 if (r_glsl_permutation->loc_FogColor >= 0)
1926 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1927 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);
1931 if (mode == SHADERMODE_FLATCOLOR)
1933 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]);
1935 else if (mode == SHADERMODE_LIGHTGRID)
1937 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]);
1938 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]);
1939 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]);
1940 // other LightGrid uniforms handled below
1942 else if (mode == SHADERMODE_LIGHTDIRECTION)
1944 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]);
1945 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]);
1946 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]);
1947 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]);
1948 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]);
1949 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1950 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir_local[0], t->render_modellight_lightdir_local[1], t->render_modellight_lightdir_local[2]);
1954 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]);
1955 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]);
1956 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]);
1957 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]);
1958 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]);
1960 // additive passes are only darkened by fog, not tinted
1961 if (r_glsl_permutation->loc_FogColor >= 0 && !notrippy)
1963 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1964 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1966 qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1968 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);
1969 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]);
1970 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]);
1971 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);
1972 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);
1973 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1974 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1975 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);
1976 if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1978 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1979 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1980 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1981 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1983 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]);
1984 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]);
1988 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]);
1989 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]);
1992 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]);
1993 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));
1994 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1995 if (r_glsl_permutation->loc_Color_Pants >= 0)
1997 if (t->pantstexture)
1998 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2000 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2002 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2004 if (t->shirttexture)
2005 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2007 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2009 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]);
2010 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2011 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2012 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2013 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2014 r_glsl_offsetmapping_scale.value*t->offsetscale,
2015 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2016 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2017 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2019 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);
2020 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2021 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]);
2022 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2023 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);}
2024 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2025 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2028 Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2029 Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2030 qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2031 Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2032 Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2033 m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2034 m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2035 m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2036 qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2039 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_texture_white );
2040 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_texture_white );
2041 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps , r_texture_gammaramps );
2042 if (r_glsl_permutation->tex_Texture_Normal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal , t->nmaptexture );
2043 if (r_glsl_permutation->tex_Texture_Color >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color , t->basetexture );
2044 if (r_glsl_permutation->tex_Texture_Gloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss , t->glosstexture );
2045 if (r_glsl_permutation->tex_Texture_Glow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow , t->glowtexture );
2046 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal , t->backgroundnmaptexture );
2047 if (r_glsl_permutation->tex_Texture_SecondaryColor >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor , t->backgroundbasetexture );
2048 if (r_glsl_permutation->tex_Texture_SecondaryGloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss , t->backgroundglosstexture );
2049 if (r_glsl_permutation->tex_Texture_SecondaryGlow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow , t->backgroundglowtexture );
2050 if (r_glsl_permutation->tex_Texture_Pants >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants , t->pantstexture );
2051 if (r_glsl_permutation->tex_Texture_Shirt >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt , t->shirttexture );
2052 if (r_glsl_permutation->tex_Texture_ReflectMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask , t->reflectmasktexture );
2053 if (r_glsl_permutation->tex_Texture_ReflectCube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2054 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture );
2055 if (r_glsl_permutation->tex_Texture_FogMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask , r_texture_fogattenuation );
2056 if (r_glsl_permutation->tex_Texture_Lightmap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2057 if (r_glsl_permutation->tex_Texture_Deluxemap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2058 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2059 if (rsurfacepass == RSURFPASS_BACKGROUND)
2061 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);
2062 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);
2063 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);
2067 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);
2069 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2070 if (r_glsl_permutation->tex_Texture_ScreenDiffuse >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse , r_shadow_prepasslightingdiffusetexture );
2071 if (r_glsl_permutation->tex_Texture_ScreenSpecular >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture );
2072 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2074 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture );
2075 if (rsurface.rtlight)
2077 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2078 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2081 if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2082 if (r_glsl_permutation->tex_Texture_LightGrid >= 0 && r_refdef.scene.worldmodel) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LightGrid, r_refdef.scene.worldmodel->brushq3.lightgridtexture);
2088 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2090 // select a permutation of the lighting shader appropriate to this
2091 // combination of texture, entity, light source, and fogging, only use the
2092 // minimum features necessary to avoid wasting rendering time in the
2093 // fragment shader on features that are not being used
2094 uint64_t permutation = 0;
2095 unsigned int mode = 0;
2096 const float *lightcolorbase = rtlight->currentcolor;
2097 float ambientscale = rtlight->ambientscale;
2098 float diffusescale = rtlight->diffusescale;
2099 float specularscale = rtlight->specularscale;
2100 // this is the location of the light in view space
2101 vec3_t viewlightorigin;
2102 // this transforms from view space (camera) to light space (cubemap)
2103 matrix4x4_t viewtolight;
2104 matrix4x4_t lighttoview;
2105 float viewtolight16f[16];
2107 mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2108 if (rtlight->currentcubemap != r_texture_whitecube)
2109 permutation |= SHADERPERMUTATION_CUBEFILTER;
2110 if (diffusescale > 0)
2111 permutation |= SHADERPERMUTATION_DIFFUSE;
2112 if (specularscale > 0 && r_shadow_gloss.integer > 0)
2113 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2114 if (r_shadow_usingshadowmap2d)
2116 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2117 if (r_shadow_shadowmapvsdct)
2118 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2120 if (r_shadow_shadowmap2ddepthbuffer)
2121 permutation |= SHADERPERMUTATION_DEPTHRGB;
2123 if (vid.allowalphatocoverage)
2124 GL_AlphaToCoverage(false);
2125 Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2126 Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2127 Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2128 Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2129 switch(vid.renderpath)
2131 case RENDERPATH_GL32:
2132 case RENDERPATH_GLES2:
2133 R_SetupShader_SetPermutationGLSL(mode, permutation);
2134 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f( r_glsl_permutation->loc_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2135 if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight , 1, false, viewtolight16f);
2136 if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2137 if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2138 if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2139 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]);
2140 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]);
2141 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);
2142 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]);
2143 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2145 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2146 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2147 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2148 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2ddepthtexture );
2149 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2154 #define SKINFRAME_HASH 1024
2158 unsigned int loadsequence; // incremented each level change
2159 memexpandablearray_t array;
2160 skinframe_t *hash[SKINFRAME_HASH];
2163 r_skinframe_t r_skinframe;
2165 void R_SkinFrame_PrepareForPurge(void)
2167 r_skinframe.loadsequence++;
2168 // wrap it without hitting zero
2169 if (r_skinframe.loadsequence >= 200)
2170 r_skinframe.loadsequence = 1;
2173 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2177 // mark the skinframe as used for the purging code
2178 skinframe->loadsequence = r_skinframe.loadsequence;
2181 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2185 if (s->merged == s->base)
2187 R_PurgeTexture(s->stain); s->stain = NULL;
2188 R_PurgeTexture(s->merged); s->merged = NULL;
2189 R_PurgeTexture(s->base); s->base = NULL;
2190 R_PurgeTexture(s->pants); s->pants = NULL;
2191 R_PurgeTexture(s->shirt); s->shirt = NULL;
2192 R_PurgeTexture(s->nmap); s->nmap = NULL;
2193 R_PurgeTexture(s->gloss); s->gloss = NULL;
2194 R_PurgeTexture(s->glow); s->glow = NULL;
2195 R_PurgeTexture(s->fog); s->fog = NULL;
2196 R_PurgeTexture(s->reflect); s->reflect = NULL;
2197 s->loadsequence = 0;
2200 void R_SkinFrame_Purge(void)
2204 for (i = 0;i < SKINFRAME_HASH;i++)
2206 for (s = r_skinframe.hash[i];s;s = s->next)
2208 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2209 R_SkinFrame_PurgeSkinFrame(s);
2214 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2216 char basename[MAX_QPATH];
2218 Image_StripImageExtension(name, basename, sizeof(basename));
2220 if( last == NULL ) {
2222 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2223 item = r_skinframe.hash[hashindex];
2228 // linearly search through the hash bucket
2229 for( ; item ; item = item->next ) {
2230 if( !strcmp( item->basename, basename ) ) {
2237 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2240 int compareflags = textureflags & TEXF_IMPORTANTBITS;
2242 char basename[MAX_QPATH];
2244 Image_StripImageExtension(name, basename, sizeof(basename));
2246 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2247 for (item = r_skinframe.hash[hashindex];item;item = item->next)
2248 if (!strcmp(item->basename, basename) &&
2249 item->textureflags == compareflags &&
2250 item->comparewidth == comparewidth &&
2251 item->compareheight == compareheight &&
2252 item->comparecrc == comparecrc)
2259 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2260 memset(item, 0, sizeof(*item));
2261 strlcpy(item->basename, basename, sizeof(item->basename));
2262 item->textureflags = compareflags;
2263 item->comparewidth = comparewidth;
2264 item->compareheight = compareheight;
2265 item->comparecrc = comparecrc;
2266 item->next = r_skinframe.hash[hashindex];
2267 r_skinframe.hash[hashindex] = item;
2269 else if (textureflags & TEXF_FORCE_RELOAD)
2270 R_SkinFrame_PurgeSkinFrame(item);
2272 R_SkinFrame_MarkUsed(item);
2276 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2278 unsigned long long avgcolor[5], wsum; \
2286 for(pix = 0; pix < cnt; ++pix) \
2289 for(comp = 0; comp < 3; ++comp) \
2291 if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2294 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2296 for(comp = 0; comp < 3; ++comp) \
2297 avgcolor[comp] += getpixel * w; \
2300 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2301 avgcolor[4] += getpixel; \
2303 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2305 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2306 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2307 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2308 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2311 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2313 skinframe_t *skinframe;
2315 if (cls.state == ca_dedicated)
2318 // return an existing skinframe if already loaded
2319 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2320 if (skinframe && skinframe->base)
2323 // if the skinframe doesn't exist this will create it
2324 return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2327 extern cvar_t gl_picmip;
2328 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2331 unsigned char *pixels;
2332 unsigned char *bumppixels;
2333 unsigned char *basepixels = NULL;
2334 int basepixels_width = 0;
2335 int basepixels_height = 0;
2336 rtexture_t *ddsbase = NULL;
2337 qbool ddshasalpha = false;
2338 float ddsavgcolor[4];
2339 char basename[MAX_QPATH];
2340 int miplevel = R_PicmipForFlags(textureflags);
2341 int savemiplevel = miplevel;
2345 if (cls.state == ca_dedicated)
2348 Image_StripImageExtension(name, basename, sizeof(basename));
2350 // check for DDS texture file first
2351 if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2353 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2354 if (basepixels == NULL && fallbacknotexture)
2355 basepixels = Image_GenerateNoTexture();
2356 if (basepixels == NULL)
2360 // FIXME handle miplevel
2362 if (developer_loading.integer)
2363 Con_Printf("loading skin \"%s\"\n", name);
2365 // we've got some pixels to store, so really allocate this new texture now
2367 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2368 textureflags &= ~TEXF_FORCE_RELOAD;
2369 skinframe->stain = NULL;
2370 skinframe->merged = NULL;
2371 skinframe->base = NULL;
2372 skinframe->pants = NULL;
2373 skinframe->shirt = NULL;
2374 skinframe->nmap = NULL;
2375 skinframe->gloss = NULL;
2376 skinframe->glow = NULL;
2377 skinframe->fog = NULL;
2378 skinframe->reflect = NULL;
2379 skinframe->hasalpha = false;
2380 // we could store the q2animname here too
2384 skinframe->base = ddsbase;
2385 skinframe->hasalpha = ddshasalpha;
2386 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2387 if (r_loadfog && skinframe->hasalpha)
2388 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);
2389 //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]);
2393 basepixels_width = image_width;
2394 basepixels_height = image_height;
2395 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);
2396 if (textureflags & TEXF_ALPHA)
2398 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2400 if (basepixels[j] < 255)
2402 skinframe->hasalpha = true;
2406 if (r_loadfog && skinframe->hasalpha)
2408 // has transparent pixels
2409 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2410 for (j = 0;j < image_width * image_height * 4;j += 4)
2415 pixels[j+3] = basepixels[j+3];
2417 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);
2421 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2423 //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]);
2424 if (r_savedds && skinframe->base)
2425 R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2426 if (r_savedds && skinframe->fog)
2427 R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2433 mymiplevel = savemiplevel;
2434 if (r_loadnormalmap)
2435 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);
2436 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2438 skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2439 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2440 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2441 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2444 // _norm is the name used by tenebrae and has been adopted as standard
2445 if (r_loadnormalmap && skinframe->nmap == NULL)
2447 mymiplevel = savemiplevel;
2448 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2450 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);
2454 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2456 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2457 Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2458 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);
2460 Mem_Free(bumppixels);
2462 else if (r_shadow_bumpscale_basetexture.value > 0)
2464 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2465 Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2466 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);
2470 if (r_savedds && skinframe->nmap)
2471 R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2475 // _luma is supported only for tenebrae compatibility
2476 // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2477 // _glow is the preferred name
2478 mymiplevel = savemiplevel;
2479 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.blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2481 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);
2483 if (r_savedds && skinframe->glow)
2484 R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2486 Mem_Free(pixels);pixels = NULL;
2489 mymiplevel = savemiplevel;
2490 if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2492 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);
2494 if (r_savedds && skinframe->gloss)
2495 R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2501 mymiplevel = savemiplevel;
2502 if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2504 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);
2506 if (r_savedds && skinframe->pants)
2507 R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2513 mymiplevel = savemiplevel;
2514 if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2516 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);
2518 if (r_savedds && skinframe->shirt)
2519 R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2525 mymiplevel = savemiplevel;
2526 if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2528 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);
2530 if (r_savedds && skinframe->reflect)
2531 R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2538 Mem_Free(basepixels);
2543 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qbool sRGB)
2546 skinframe_t *skinframe;
2549 if (cls.state == ca_dedicated)
2552 // if already loaded just return it, otherwise make a new skinframe
2553 skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2554 if (skinframe->base)
2556 textureflags &= ~TEXF_FORCE_RELOAD;
2558 skinframe->stain = NULL;
2559 skinframe->merged = NULL;
2560 skinframe->base = NULL;
2561 skinframe->pants = NULL;
2562 skinframe->shirt = NULL;
2563 skinframe->nmap = NULL;
2564 skinframe->gloss = NULL;
2565 skinframe->glow = NULL;
2566 skinframe->fog = NULL;
2567 skinframe->reflect = NULL;
2568 skinframe->hasalpha = false;
2570 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2574 if (developer_loading.integer)
2575 Con_Printf("loading 32bit skin \"%s\"\n", name);
2577 if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2579 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2580 unsigned char *b = a + width * height * 4;
2581 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2582 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);
2585 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2586 if (textureflags & TEXF_ALPHA)
2588 for (i = 3;i < width * height * 4;i += 4)
2590 if (skindata[i] < 255)
2592 skinframe->hasalpha = true;
2596 if (r_loadfog && skinframe->hasalpha)
2598 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2599 memcpy(fogpixels, skindata, width * height * 4);
2600 for (i = 0;i < width * height * 4;i += 4)
2601 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2602 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2603 Mem_Free(fogpixels);
2607 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2608 //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]);
2613 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2617 skinframe_t *skinframe;
2619 if (cls.state == ca_dedicated)
2622 // if already loaded just return it, otherwise make a new skinframe
2623 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2624 if (skinframe->base)
2626 //textureflags &= ~TEXF_FORCE_RELOAD;
2628 skinframe->stain = NULL;
2629 skinframe->merged = NULL;
2630 skinframe->base = NULL;
2631 skinframe->pants = NULL;
2632 skinframe->shirt = NULL;
2633 skinframe->nmap = NULL;
2634 skinframe->gloss = NULL;
2635 skinframe->glow = NULL;
2636 skinframe->fog = NULL;
2637 skinframe->reflect = NULL;
2638 skinframe->hasalpha = false;
2640 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2644 if (developer_loading.integer)
2645 Con_Printf("loading quake skin \"%s\"\n", name);
2647 // 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)
2648 skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2649 memcpy(skinframe->qpixels, skindata, width*height);
2650 skinframe->qwidth = width;
2651 skinframe->qheight = height;
2654 for (i = 0;i < width * height;i++)
2655 featuresmask |= palette_featureflags[skindata[i]];
2657 skinframe->hasalpha = false;
2660 skinframe->hasalpha = true;
2661 skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2662 skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2663 skinframe->qgeneratemerged = true;
2664 skinframe->qgeneratebase = skinframe->qhascolormapping;
2665 skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2667 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2668 //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]);
2673 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2677 unsigned char *skindata;
2680 if (!skinframe->qpixels)
2683 if (!skinframe->qhascolormapping)
2684 colormapped = false;
2688 if (!skinframe->qgeneratebase)
2693 if (!skinframe->qgeneratemerged)
2697 width = skinframe->qwidth;
2698 height = skinframe->qheight;
2699 skindata = skinframe->qpixels;
2701 if (skinframe->qgeneratenmap)
2703 unsigned char *a, *b;
2704 skinframe->qgeneratenmap = false;
2705 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2706 b = a + width * height * 4;
2707 // use either a custom palette or the quake palette
2708 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2709 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2710 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);
2714 if (skinframe->qgenerateglow)
2716 skinframe->qgenerateglow = false;
2717 if (skinframe->hasalpha) // fence textures
2718 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
2720 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
2725 skinframe->qgeneratebase = false;
2726 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);
2727 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);
2728 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);
2732 skinframe->qgeneratemerged = false;
2733 if (skinframe->hasalpha) // fence textures
2734 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);
2736 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);
2739 if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2741 Mem_Free(skinframe->qpixels);
2742 skinframe->qpixels = NULL;
2746 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)
2749 skinframe_t *skinframe;
2752 if (cls.state == ca_dedicated)
2755 // if already loaded just return it, otherwise make a new skinframe
2756 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2757 if (skinframe->base)
2759 textureflags &= ~TEXF_FORCE_RELOAD;
2761 skinframe->stain = NULL;
2762 skinframe->merged = NULL;
2763 skinframe->base = NULL;
2764 skinframe->pants = NULL;
2765 skinframe->shirt = NULL;
2766 skinframe->nmap = NULL;
2767 skinframe->gloss = NULL;
2768 skinframe->glow = NULL;
2769 skinframe->fog = NULL;
2770 skinframe->reflect = NULL;
2771 skinframe->hasalpha = false;
2773 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2777 if (developer_loading.integer)
2778 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2780 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2781 if ((textureflags & TEXF_ALPHA) && alphapalette)
2783 for (i = 0;i < width * height;i++)
2785 if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2787 skinframe->hasalpha = true;
2791 if (r_loadfog && skinframe->hasalpha)
2792 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2795 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2796 //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]);
2801 skinframe_t *R_SkinFrame_LoadMissing(void)
2803 skinframe_t *skinframe;
2805 if (cls.state == ca_dedicated)
2808 skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2809 skinframe->stain = NULL;
2810 skinframe->merged = NULL;
2811 skinframe->base = NULL;
2812 skinframe->pants = NULL;
2813 skinframe->shirt = NULL;
2814 skinframe->nmap = NULL;
2815 skinframe->gloss = NULL;
2816 skinframe->glow = NULL;
2817 skinframe->fog = NULL;
2818 skinframe->reflect = NULL;
2819 skinframe->hasalpha = false;
2821 skinframe->avgcolor[0] = rand() / RAND_MAX;
2822 skinframe->avgcolor[1] = rand() / RAND_MAX;
2823 skinframe->avgcolor[2] = rand() / RAND_MAX;
2824 skinframe->avgcolor[3] = 1;
2829 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2831 if (cls.state == ca_dedicated)
2834 return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2837 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2839 skinframe_t *skinframe;
2840 if (cls.state == ca_dedicated)
2842 // if already loaded just return it, otherwise make a new skinframe
2843 skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2844 if (skinframe->base)
2846 textureflags &= ~TEXF_FORCE_RELOAD;
2847 skinframe->stain = NULL;
2848 skinframe->merged = NULL;
2849 skinframe->base = NULL;
2850 skinframe->pants = NULL;
2851 skinframe->shirt = NULL;
2852 skinframe->nmap = NULL;
2853 skinframe->gloss = NULL;
2854 skinframe->glow = NULL;
2855 skinframe->fog = NULL;
2856 skinframe->reflect = NULL;
2857 skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2858 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2861 if (developer_loading.integer)
2862 Con_Printf("loading 32bit skin \"%s\"\n", name);
2863 skinframe->base = skinframe->merged = tex;
2864 Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2868 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2869 typedef struct suffixinfo_s
2872 qbool flipx, flipy, flipdiagonal;
2875 static suffixinfo_t suffix[3][6] =
2878 {"px", false, false, false},
2879 {"nx", false, false, false},
2880 {"py", false, false, false},
2881 {"ny", false, false, false},
2882 {"pz", false, false, false},
2883 {"nz", false, false, false}
2886 {"posx", false, false, false},
2887 {"negx", false, false, false},
2888 {"posy", false, false, false},
2889 {"negy", false, false, false},
2890 {"posz", false, false, false},
2891 {"negz", false, false, false}
2894 {"rt", true, false, true},
2895 {"lf", false, true, true},
2896 {"ft", true, true, false},
2897 {"bk", false, false, false},
2898 {"up", true, false, true},
2899 {"dn", true, false, true}
2903 static int componentorder[4] = {0, 1, 2, 3};
2905 static rtexture_t *R_LoadCubemap(const char *basename)
2907 int i, j, cubemapsize, forcefilter;
2908 unsigned char *cubemappixels, *image_buffer;
2909 rtexture_t *cubemaptexture;
2912 // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2913 forcefilter = TEXF_FORCELINEAR;
2914 if (basename && basename[0] == '!')
2917 forcefilter = TEXF_FORCENEAREST;
2919 // must start 0 so the first loadimagepixels has no requested width/height
2921 cubemappixels = NULL;
2922 cubemaptexture = NULL;
2923 // keep trying different suffix groups (posx, px, rt) until one loads
2924 for (j = 0;j < 3 && !cubemappixels;j++)
2926 // load the 6 images in the suffix group
2927 for (i = 0;i < 6;i++)
2929 // generate an image name based on the base and and suffix
2930 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2932 if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2934 // an image loaded, make sure width and height are equal
2935 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2937 // if this is the first image to load successfully, allocate the cubemap memory
2938 if (!cubemappixels && image_width >= 1)
2940 cubemapsize = image_width;
2941 // note this clears to black, so unavailable sides are black
2942 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2944 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2946 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);
2949 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2951 Mem_Free(image_buffer);
2955 // if a cubemap loaded, upload it
2958 if (developer_loading.integer)
2959 Con_Printf("loading cubemap \"%s\"\n", basename);
2961 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) | forcefilter | TEXF_CLAMP, -1, NULL);
2962 Mem_Free(cubemappixels);
2966 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2967 if (developer_loading.integer)
2969 Con_Printf("(tried tried images ");
2970 for (j = 0;j < 3;j++)
2971 for (i = 0;i < 6;i++)
2972 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2973 Con_Print(" and was unable to find any of them).\n");
2976 return cubemaptexture;
2979 rtexture_t *R_GetCubemap(const char *basename)
2982 for (i = 0;i < r_texture_numcubemaps;i++)
2983 if (r_texture_cubemaps[i] != NULL)
2984 if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2985 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2986 if (i >= MAX_CUBEMAPS || !r_main_mempool)
2987 return r_texture_whitecube;
2988 r_texture_numcubemaps++;
2989 r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2990 strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2991 r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2992 return r_texture_cubemaps[i]->texture;
2995 static void R_Main_FreeViewCache(void)
2997 if (r_refdef.viewcache.entityvisible)
2998 Mem_Free(r_refdef.viewcache.entityvisible);
2999 if (r_refdef.viewcache.world_pvsbits)
3000 Mem_Free(r_refdef.viewcache.world_pvsbits);
3001 if (r_refdef.viewcache.world_leafvisible)
3002 Mem_Free(r_refdef.viewcache.world_leafvisible);
3003 if (r_refdef.viewcache.world_surfacevisible)
3004 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3005 memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3008 static void R_Main_ResizeViewCache(void)
3010 int numentities = r_refdef.scene.numentities;
3011 int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3012 int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3013 int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3014 int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3015 if (r_refdef.viewcache.maxentities < numentities)
3017 r_refdef.viewcache.maxentities = numentities;
3018 if (r_refdef.viewcache.entityvisible)
3019 Mem_Free(r_refdef.viewcache.entityvisible);
3020 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3022 if (r_refdef.viewcache.world_numclusters != numclusters)
3024 r_refdef.viewcache.world_numclusters = numclusters;
3025 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3026 if (r_refdef.viewcache.world_pvsbits)
3027 Mem_Free(r_refdef.viewcache.world_pvsbits);
3028 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3030 if (r_refdef.viewcache.world_numleafs != numleafs)
3032 r_refdef.viewcache.world_numleafs = numleafs;
3033 if (r_refdef.viewcache.world_leafvisible)
3034 Mem_Free(r_refdef.viewcache.world_leafvisible);
3035 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3037 if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3039 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3040 if (r_refdef.viewcache.world_surfacevisible)
3041 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3042 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3046 extern rtexture_t *loadingscreentexture;
3047 static void gl_main_start(void)
3049 loadingscreentexture = NULL;
3050 r_texture_blanknormalmap = NULL;
3051 r_texture_white = NULL;
3052 r_texture_grey128 = NULL;
3053 r_texture_black = NULL;
3054 r_texture_whitecube = NULL;
3055 r_texture_normalizationcube = NULL;
3056 r_texture_fogattenuation = NULL;
3057 r_texture_fogheighttexture = NULL;
3058 r_texture_gammaramps = NULL;
3059 r_texture_numcubemaps = 0;
3060 r_uniformbufferalignment = 32;
3062 r_loaddds = r_texture_dds_load.integer != 0;
3063 r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3065 switch(vid.renderpath)
3067 case RENDERPATH_GL32:
3068 case RENDERPATH_GLES2:
3069 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3070 Cvar_SetValueQuick(&gl_combine, 1);
3071 Cvar_SetValueQuick(&r_glsl, 1);
3072 r_loadnormalmap = true;
3075 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3076 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3082 R_FrameData_Reset();
3083 R_BufferData_Reset();
3087 memset(r_queries, 0, sizeof(r_queries));
3089 r_qwskincache = NULL;
3090 r_qwskincache_size = 0;
3092 // due to caching of texture_t references, the collision cache must be reset
3093 Collision_Cache_Reset(true);
3095 // set up r_skinframe loading system for textures
3096 memset(&r_skinframe, 0, sizeof(r_skinframe));
3097 r_skinframe.loadsequence = 1;
3098 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3100 r_main_texturepool = R_AllocTexturePool();
3101 R_BuildBlankTextures();
3105 R_BuildNormalizationCube();
3107 r_texture_fogattenuation = NULL;
3108 r_texture_fogheighttexture = NULL;
3109 r_texture_gammaramps = NULL;
3110 //r_texture_fogintensity = NULL;
3111 memset(&r_fb, 0, sizeof(r_fb));
3112 Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3113 r_glsl_permutation = NULL;
3114 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3115 Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3116 memset(&r_svbsp, 0, sizeof (r_svbsp));
3118 memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3119 r_texture_numcubemaps = 0;
3121 r_refdef.fogmasktable_density = 0;
3124 // For Steelstorm Android
3125 // FIXME CACHE the program and reload
3126 // FIXME see possible combinations for SS:BR android
3127 Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3128 R_SetupShader_SetPermutationGLSL(0, 12);
3129 R_SetupShader_SetPermutationGLSL(0, 13);
3130 R_SetupShader_SetPermutationGLSL(0, 8388621);
3131 R_SetupShader_SetPermutationGLSL(3, 0);
3132 R_SetupShader_SetPermutationGLSL(3, 2048);
3133 R_SetupShader_SetPermutationGLSL(5, 0);
3134 R_SetupShader_SetPermutationGLSL(5, 2);
3135 R_SetupShader_SetPermutationGLSL(5, 2048);
3136 R_SetupShader_SetPermutationGLSL(5, 8388608);
3137 R_SetupShader_SetPermutationGLSL(11, 1);
3138 R_SetupShader_SetPermutationGLSL(11, 2049);
3139 R_SetupShader_SetPermutationGLSL(11, 8193);
3140 R_SetupShader_SetPermutationGLSL(11, 10241);
3141 Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3145 extern unsigned int r_shadow_occlusion_buf;
3147 static void gl_main_shutdown(void)
3149 R_RenderTarget_FreeUnused(true);
3150 Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3152 R_FrameData_Reset();
3153 R_BufferData_Reset();
3155 R_Main_FreeViewCache();
3157 switch(vid.renderpath)
3159 case RENDERPATH_GL32:
3160 case RENDERPATH_GLES2:
3161 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3163 qglDeleteQueries(r_maxqueries, r_queries);
3167 r_shadow_occlusion_buf = 0;
3170 memset(r_queries, 0, sizeof(r_queries));
3172 r_qwskincache = NULL;
3173 r_qwskincache_size = 0;
3175 // clear out the r_skinframe state
3176 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3177 memset(&r_skinframe, 0, sizeof(r_skinframe));
3180 Mem_Free(r_svbsp.nodes);
3181 memset(&r_svbsp, 0, sizeof (r_svbsp));
3182 R_FreeTexturePool(&r_main_texturepool);
3183 loadingscreentexture = NULL;
3184 r_texture_blanknormalmap = NULL;
3185 r_texture_white = NULL;
3186 r_texture_grey128 = NULL;
3187 r_texture_black = NULL;
3188 r_texture_whitecube = NULL;
3189 r_texture_normalizationcube = NULL;
3190 r_texture_fogattenuation = NULL;
3191 r_texture_fogheighttexture = NULL;
3192 r_texture_gammaramps = NULL;
3193 r_texture_numcubemaps = 0;
3194 //r_texture_fogintensity = NULL;
3195 memset(&r_fb, 0, sizeof(r_fb));
3196 R_GLSL_Restart_f(&cmd_client);
3198 r_glsl_permutation = NULL;
3199 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3200 Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3203 static void gl_main_newmap(void)
3205 // FIXME: move this code to client
3206 char *entities, entname[MAX_QPATH];
3208 Mem_Free(r_qwskincache);
3209 r_qwskincache = NULL;
3210 r_qwskincache_size = 0;
3213 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3214 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3216 CL_ParseEntityLump(entities);
3220 if (cl.worldmodel->brush.entities)
3221 CL_ParseEntityLump(cl.worldmodel->brush.entities);
3223 R_Main_FreeViewCache();
3225 R_FrameData_Reset();
3226 R_BufferData_Reset();
3229 void GL_Main_Init(void)
3232 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3233 R_InitShaderModeInfo();
3235 Cmd_AddCommand(CF_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3236 Cmd_AddCommand(CF_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3237 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3238 if (gamemode == GAME_NEHAHRA)
3240 Cvar_RegisterVariable (&gl_fogenable);
3241 Cvar_RegisterVariable (&gl_fogdensity);
3242 Cvar_RegisterVariable (&gl_fogred);
3243 Cvar_RegisterVariable (&gl_foggreen);
3244 Cvar_RegisterVariable (&gl_fogblue);
3245 Cvar_RegisterVariable (&gl_fogstart);
3246 Cvar_RegisterVariable (&gl_fogend);
3247 Cvar_RegisterVariable (&gl_skyclip);
3249 Cvar_RegisterVariable(&r_motionblur);
3250 Cvar_RegisterVariable(&r_damageblur);
3251 Cvar_RegisterVariable(&r_motionblur_averaging);
3252 Cvar_RegisterVariable(&r_motionblur_randomize);
3253 Cvar_RegisterVariable(&r_motionblur_minblur);
3254 Cvar_RegisterVariable(&r_motionblur_maxblur);
3255 Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3256 Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3257 Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3258 Cvar_RegisterVariable(&r_motionblur_mousefactor);
3259 Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3260 Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3261 Cvar_RegisterVariable(&r_depthfirst);
3262 Cvar_RegisterVariable(&r_useinfinitefarclip);
3263 Cvar_RegisterVariable(&r_farclip_base);
3264 Cvar_RegisterVariable(&r_farclip_world);
3265 Cvar_RegisterVariable(&r_nearclip);
3266 Cvar_RegisterVariable(&r_deformvertexes);
3267 Cvar_RegisterVariable(&r_transparent);
3268 Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3269 Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3270 Cvar_RegisterVariable(&r_transparent_useplanardistance);
3271 Cvar_RegisterVariable(&r_showoverdraw);
3272 Cvar_RegisterVariable(&r_showbboxes);
3273 Cvar_RegisterVariable(&r_showbboxes_client);
3274 Cvar_RegisterVariable(&r_showsurfaces);
3275 Cvar_RegisterVariable(&r_showtris);
3276 Cvar_RegisterVariable(&r_shownormals);
3277 Cvar_RegisterVariable(&r_showlighting);
3278 Cvar_RegisterVariable(&r_showcollisionbrushes);
3279 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3280 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3281 Cvar_RegisterVariable(&r_showdisabledepthtest);
3282 Cvar_RegisterVariable(&r_showspriteedges);
3283 Cvar_RegisterVariable(&r_showparticleedges);
3284 Cvar_RegisterVariable(&r_drawportals);
3285 Cvar_RegisterVariable(&r_drawentities);
3286 Cvar_RegisterVariable(&r_draw2d);
3287 Cvar_RegisterVariable(&r_drawworld);
3288 Cvar_RegisterVariable(&r_cullentities_trace);
3289 Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3290 Cvar_RegisterVariable(&r_cullentities_trace_samples);
3291 Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3292 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3293 Cvar_RegisterVariable(&r_cullentities_trace_expand);
3294 Cvar_RegisterVariable(&r_cullentities_trace_pad);
3295 Cvar_RegisterVariable(&r_cullentities_trace_delay);
3296 Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3297 Cvar_RegisterVariable(&r_sortentities);
3298 Cvar_RegisterVariable(&r_drawviewmodel);
3299 Cvar_RegisterVariable(&r_drawexteriormodel);
3300 Cvar_RegisterVariable(&r_speeds);
3301 Cvar_RegisterVariable(&r_fullbrights);
3302 Cvar_RegisterVariable(&r_wateralpha);
3303 Cvar_RegisterVariable(&r_dynamic);
3304 Cvar_RegisterVariable(&r_fullbright_directed);
3305 Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3306 Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3307 Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3308 Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3309 Cvar_RegisterVariable(&r_fullbright);
3310 Cvar_RegisterVariable(&r_shadows);
3311 Cvar_RegisterVariable(&r_shadows_darken);
3312 Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3313 Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3314 Cvar_RegisterVariable(&r_shadows_throwdistance);
3315 Cvar_RegisterVariable(&r_shadows_throwdirection);
3316 Cvar_RegisterVariable(&r_shadows_focus);
3317 Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3318 Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3319 Cvar_RegisterVariable(&r_q1bsp_skymasking);
3320 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3321 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3322 Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3323 Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3324 Cvar_RegisterVariable(&r_fog_exp2);
3325 Cvar_RegisterVariable(&r_fog_clear);
3326 Cvar_RegisterVariable(&r_drawfog);
3327 Cvar_RegisterVariable(&r_transparentdepthmasking);
3328 Cvar_RegisterVariable(&r_transparent_sortmindist);
3329 Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3330 Cvar_RegisterVariable(&r_transparent_sortarraysize);
3331 Cvar_RegisterVariable(&r_texture_dds_load);
3332 Cvar_RegisterVariable(&r_texture_dds_save);
3333 Cvar_RegisterVariable(&r_textureunits);
3334 Cvar_RegisterVariable(&gl_combine);
3335 Cvar_RegisterVariable(&r_usedepthtextures);
3336 Cvar_RegisterVariable(&r_viewfbo);
3337 Cvar_RegisterVariable(&r_rendertarget_debug);
3338 Cvar_RegisterVariable(&r_viewscale);
3339 Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3340 Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3341 Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3342 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3343 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3344 Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3345 Cvar_RegisterVariable(&r_glsl);
3346 Cvar_RegisterVariable(&r_glsl_deluxemapping);
3347 Cvar_RegisterVariable(&r_glsl_offsetmapping);
3348 Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3349 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3350 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3351 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3352 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3353 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3354 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3355 Cvar_RegisterVariable(&r_glsl_postprocess);
3356 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3357 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3358 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3359 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3360 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3361 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3362 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3363 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3364 Cvar_RegisterVariable(&r_celshading);
3365 Cvar_RegisterVariable(&r_celoutlines);
3367 Cvar_RegisterVariable(&r_water);
3368 Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3369 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3370 Cvar_RegisterVariable(&r_water_clippingplanebias);
3371 Cvar_RegisterVariable(&r_water_refractdistort);
3372 Cvar_RegisterVariable(&r_water_reflectdistort);
3373 Cvar_RegisterVariable(&r_water_scissormode);
3374 Cvar_RegisterVariable(&r_water_lowquality);
3375 Cvar_RegisterVariable(&r_water_hideplayer);
3377 Cvar_RegisterVariable(&r_lerpsprites);
3378 Cvar_RegisterVariable(&r_lerpmodels);
3379 Cvar_RegisterVariable(&r_nolerp_list);
3380 Cvar_RegisterVariable(&r_lerplightstyles);
3381 Cvar_RegisterVariable(&r_waterscroll);
3382 Cvar_RegisterVariable(&r_bloom);
3383 Cvar_RegisterVariable(&r_colorfringe);
3384 Cvar_RegisterVariable(&r_bloom_colorscale);
3385 Cvar_RegisterVariable(&r_bloom_brighten);
3386 Cvar_RegisterVariable(&r_bloom_blur);
3387 Cvar_RegisterVariable(&r_bloom_resolution);
3388 Cvar_RegisterVariable(&r_bloom_colorexponent);
3389 Cvar_RegisterVariable(&r_bloom_colorsubtract);
3390 Cvar_RegisterVariable(&r_bloom_scenebrightness);
3391 Cvar_RegisterVariable(&r_hdr_scenebrightness);
3392 Cvar_RegisterVariable(&r_hdr_glowintensity);
3393 Cvar_RegisterVariable(&r_hdr_irisadaptation);
3394 Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3395 Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3396 Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3397 Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3398 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3399 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3400 Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3401 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3402 Cvar_RegisterVariable(&developer_texturelogging);
3403 Cvar_RegisterVariable(&gl_lightmaps);
3404 Cvar_RegisterVariable(&r_test);
3405 Cvar_RegisterVariable(&r_batch_multidraw);
3406 Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3407 Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3408 Cvar_RegisterVariable(&r_glsl_skeletal);
3409 Cvar_RegisterVariable(&r_glsl_saturation);
3410 Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3411 Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3412 Cvar_RegisterVariable(&r_framedatasize);
3413 for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3414 Cvar_RegisterVariable(&r_buffermegs[i]);
3415 Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3416 Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3417 Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3418 Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3419 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3420 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3421 #ifdef DP_MOBILETOUCH
3422 // GLES devices have terrible depth precision in general, so...
3423 Cvar_SetValueQuick(&r_nearclip, 4);
3424 Cvar_SetValueQuick(&r_farclip_base, 4096);
3425 Cvar_SetValueQuick(&r_farclip_world, 0);
3426 Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3428 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3431 void Render_Init(void)
3444 R_LightningBeams_Init();
3448 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3452 if (r_trippy.integer)
3454 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3456 p = r_refdef.view.frustum + i;
3461 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3465 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3469 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3473 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3477 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3481 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3485 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3489 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3497 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3501 if (r_trippy.integer)
3503 for (i = 0;i < numplanes;i++)
3510 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3514 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3518 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3522 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3526 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3530 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3534 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3538 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3546 //==================================================================================
3548 // LadyHavoc: this stores temporary data used within the same frame
3550 typedef struct r_framedata_mem_s
3552 struct r_framedata_mem_s *purge; // older mem block to free on next frame
3553 size_t size; // how much usable space
3554 size_t current; // how much space in use
3555 size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3556 size_t wantedsize; // how much space was allocated
3557 unsigned char *data; // start of real data (16byte aligned)
3561 static r_framedata_mem_t *r_framedata_mem;
3563 void R_FrameData_Reset(void)
3565 while (r_framedata_mem)
3567 r_framedata_mem_t *next = r_framedata_mem->purge;
3568 Mem_Free(r_framedata_mem);
3569 r_framedata_mem = next;
3573 static void R_FrameData_Resize(qbool mustgrow)
3576 wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3577 wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3578 if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3580 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3581 newmem->wantedsize = wantedsize;
3582 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3583 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3584 newmem->current = 0;
3586 newmem->purge = r_framedata_mem;
3587 r_framedata_mem = newmem;
3591 void R_FrameData_NewFrame(void)
3593 R_FrameData_Resize(false);
3594 if (!r_framedata_mem)
3596 // if we ran out of space on the last frame, free the old memory now
3597 while (r_framedata_mem->purge)
3599 // repeatedly remove the second item in the list, leaving only head
3600 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3601 Mem_Free(r_framedata_mem->purge);
3602 r_framedata_mem->purge = next;
3604 // reset the current mem pointer
3605 r_framedata_mem->current = 0;
3606 r_framedata_mem->mark = 0;
3609 void *R_FrameData_Alloc(size_t size)
3614 // align to 16 byte boundary - the data pointer is already aligned, so we
3615 // only need to ensure the size of every allocation is also aligned
3616 size = (size + 15) & ~15;
3618 while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3620 // emergency - we ran out of space, allocate more memory
3621 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3622 newvalue = r_framedatasize.value * 2.0f;
3623 // 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
3624 if (sizeof(size_t) >= 8)
3625 newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3627 newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3628 // this might not be a growing it, but we'll allocate another buffer every time
3629 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3630 R_FrameData_Resize(true);
3633 data = r_framedata_mem->data + r_framedata_mem->current;
3634 r_framedata_mem->current += size;
3636 // count the usage for stats
3637 r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3638 r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3640 return (void *)data;
3643 void *R_FrameData_Store(size_t size, void *data)
3645 void *d = R_FrameData_Alloc(size);
3647 memcpy(d, data, size);
3651 void R_FrameData_SetMark(void)
3653 if (!r_framedata_mem)
3655 r_framedata_mem->mark = r_framedata_mem->current;
3658 void R_FrameData_ReturnToMark(void)
3660 if (!r_framedata_mem)
3662 r_framedata_mem->current = r_framedata_mem->mark;
3665 //==================================================================================
3667 // avoid reusing the same buffer objects on consecutive frames
3668 #define R_BUFFERDATA_CYCLE 3
3670 typedef struct r_bufferdata_buffer_s
3672 struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3673 size_t size; // how much usable space
3674 size_t current; // how much space in use
3675 r_meshbuffer_t *buffer; // the buffer itself
3677 r_bufferdata_buffer_t;
3679 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3680 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3682 /// frees all dynamic buffers
3683 void R_BufferData_Reset(void)
3686 r_bufferdata_buffer_t **p, *mem;
3687 for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3689 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3692 p = &r_bufferdata_buffer[cycle][type];
3698 R_Mesh_DestroyMeshBuffer(mem->buffer);
3705 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3706 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3708 r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3710 float newvalue = r_buffermegs[type].value;
3712 // increase the cvar if we have to (but only if we already have a mem)
3713 if (mustgrow && mem)
3715 newvalue = bound(0.25f, newvalue, 256.0f);
3716 while (newvalue * 1024*1024 < minsize)
3719 // clamp the cvar to valid range
3720 newvalue = bound(0.25f, newvalue, 256.0f);
3721 if (r_buffermegs[type].value != newvalue)
3722 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3724 // calculate size in bytes
3725 size = (size_t)(newvalue * 1024*1024);
3726 size = bound(131072, size, 256*1024*1024);
3728 // allocate a new buffer if the size is different (purge old one later)
3729 // or if we were told we must grow the buffer
3730 if (!mem || mem->size != size || mustgrow)
3732 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3735 if (type == R_BUFFERDATA_VERTEX)
3736 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3737 else if (type == R_BUFFERDATA_INDEX16)
3738 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3739 else if (type == R_BUFFERDATA_INDEX32)
3740 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3741 else if (type == R_BUFFERDATA_UNIFORM)
3742 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3743 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3744 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3748 void R_BufferData_NewFrame(void)
3751 r_bufferdata_buffer_t **p, *mem;
3752 // cycle to the next frame's buffers
3753 r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3754 // if we ran out of space on the last time we used these buffers, free the old memory now
3755 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3757 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3759 R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3760 // free all but the head buffer, this is how we recycle obsolete
3761 // buffers after they are no longer in use
3762 p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3768 R_Mesh_DestroyMeshBuffer(mem->buffer);
3771 // reset the current offset
3772 r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3777 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3779 r_bufferdata_buffer_t *mem;
3783 *returnbufferoffset = 0;
3785 // align size to a byte boundary appropriate for the buffer type, this
3786 // makes all allocations have aligned start offsets
3787 if (type == R_BUFFERDATA_UNIFORM)
3788 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3790 padsize = (datasize + 15) & ~15;
3792 // if we ran out of space in this buffer we must allocate a new one
3793 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)
3794 R_BufferData_Resize(type, true, padsize);
3796 // if the resize did not give us enough memory, fail
3797 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)
3798 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3800 mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3801 offset = (int)mem->current;
3802 mem->current += padsize;
3804 // upload the data to the buffer at the chosen offset
3806 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3807 R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3809 // count the usage for stats
3810 r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3811 r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3813 // return the buffer offset
3814 *returnbufferoffset = offset;
3819 //==================================================================================
3821 // LadyHavoc: animcache originally written by Echon, rewritten since then
3824 * Animation cache prevents re-generating mesh data for an animated model
3825 * multiple times in one frame for lighting, shadowing, reflections, etc.
3828 void R_AnimCache_Free(void)
3832 void R_AnimCache_ClearCache(void)
3835 entity_render_t *ent;
3837 for (i = 0;i < r_refdef.scene.numentities;i++)
3839 ent = r_refdef.scene.entities[i];
3840 ent->animcache_vertex3f = NULL;
3841 ent->animcache_vertex3f_vertexbuffer = NULL;
3842 ent->animcache_vertex3f_bufferoffset = 0;
3843 ent->animcache_normal3f = NULL;
3844 ent->animcache_normal3f_vertexbuffer = NULL;
3845 ent->animcache_normal3f_bufferoffset = 0;
3846 ent->animcache_svector3f = NULL;
3847 ent->animcache_svector3f_vertexbuffer = NULL;
3848 ent->animcache_svector3f_bufferoffset = 0;
3849 ent->animcache_tvector3f = NULL;
3850 ent->animcache_tvector3f_vertexbuffer = NULL;
3851 ent->animcache_tvector3f_bufferoffset = 0;
3852 ent->animcache_skeletaltransform3x4 = NULL;
3853 ent->animcache_skeletaltransform3x4buffer = NULL;
3854 ent->animcache_skeletaltransform3x4offset = 0;
3855 ent->animcache_skeletaltransform3x4size = 0;
3859 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3861 model_t *model = ent->model;
3864 // see if this ent is worth caching
3865 if (!model || !model->Draw || !model->AnimateVertices)
3867 // nothing to cache if it contains no animations and has no skeleton
3868 if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3870 // see if it is already cached for gpuskeletal
3871 if (ent->animcache_skeletaltransform3x4)
3873 // see if it is already cached as a mesh
3874 if (ent->animcache_vertex3f)
3876 // check if we need to add normals or tangents
3877 if (ent->animcache_normal3f)
3878 wantnormals = false;
3879 if (ent->animcache_svector3f)
3880 wanttangents = false;
3881 if (!wantnormals && !wanttangents)
3885 // check which kind of cache we need to generate
3886 if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3888 // cache the skeleton so the vertex shader can use it
3889 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3890 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3891 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3892 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3893 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3894 // note: this can fail if the buffer is at the grow limit
3895 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3896 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3898 else if (ent->animcache_vertex3f)
3900 // mesh was already cached but we may need to add normals/tangents
3901 // (this only happens with multiple views, reflections, cameras, etc)
3902 if (wantnormals || wanttangents)
3904 numvertices = model->surfmesh.num_vertices;
3906 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3909 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3910 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3912 model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3913 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3914 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3915 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3920 // generate mesh cache
3921 numvertices = model->surfmesh.num_vertices;
3922 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3924 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3927 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3928 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3930 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3931 if (wantnormals || wanttangents)
3933 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3934 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3935 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3937 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3938 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3939 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3944 void R_AnimCache_CacheVisibleEntities(void)
3948 // TODO: thread this
3949 // NOTE: R_PrepareRTLights() also caches entities
3951 for (i = 0;i < r_refdef.scene.numentities;i++)
3952 if (r_refdef.viewcache.entityvisible[i])
3953 R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3956 //==================================================================================
3958 qbool 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)
3960 long unsigned int i;
3962 vec3_t eyemins, eyemaxs;
3963 vec3_t boxmins, boxmaxs;
3964 vec3_t padmins, padmaxs;
3967 model_t *model = r_refdef.scene.worldmodel;
3968 static vec3_t positions[] = {
3969 { 0.5f, 0.5f, 0.5f },
3970 { 0.0f, 0.0f, 0.0f },
3971 { 0.0f, 0.0f, 1.0f },
3972 { 0.0f, 1.0f, 0.0f },
3973 { 0.0f, 1.0f, 1.0f },
3974 { 1.0f, 0.0f, 0.0f },
3975 { 1.0f, 0.0f, 1.0f },
3976 { 1.0f, 1.0f, 0.0f },
3977 { 1.0f, 1.0f, 1.0f },
3980 // sample count can be set to -1 to skip this logic, for flicker-prone objects
3984 // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3985 if (!r_refdef.view.usevieworiginculling)
3988 if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3991 // expand the eye box a little
3992 eyemins[0] = eye[0] - eyejitter;
3993 eyemaxs[0] = eye[0] + eyejitter;
3994 eyemins[1] = eye[1] - eyejitter;
3995 eyemaxs[1] = eye[1] + eyejitter;
3996 eyemins[2] = eye[2] - eyejitter;
3997 eyemaxs[2] = eye[2] + eyejitter;
3998 // expand the box a little
3999 boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4000 boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4001 boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4002 boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4003 boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4004 boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4005 // make an even larger box for the acceptable area
4006 padmins[0] = boxmins[0] - pad;
4007 padmaxs[0] = boxmaxs[0] + pad;
4008 padmins[1] = boxmins[1] - pad;
4009 padmaxs[1] = boxmaxs[1] + pad;
4010 padmins[2] = boxmins[2] - pad;
4011 padmaxs[2] = boxmaxs[2] + pad;
4013 // return true if eye overlaps enlarged box
4014 if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4017 // try specific positions in the box first - note that these can be cached
4018 if (r_cullentities_trace_entityocclusion.integer)
4020 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4023 VectorCopy(eye, start);
4024 end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4025 end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4026 end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4027 //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4028 trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4029 // not picky - if the trace ended anywhere in the box we're good
4030 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4034 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4037 // try various random positions
4038 for (j = 0; j < numsamples; j++)
4040 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4041 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4042 if (r_cullentities_trace_entityocclusion.integer)
4044 trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4045 // not picky - if the trace ended anywhere in the box we're good
4046 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4049 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4057 static void R_View_UpdateEntityVisible (void)
4062 entity_render_t *ent;
4064 if (r_refdef.envmap || r_fb.water.hideplayer)
4065 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4066 else if (chase_active.integer || r_fb.water.renderingscene)
4067 renderimask = RENDER_VIEWMODEL;
4069 renderimask = RENDER_EXTERIORMODEL;
4070 if (!r_drawviewmodel.integer)
4071 renderimask |= RENDER_VIEWMODEL;
4072 if (!r_drawexteriormodel.integer)
4073 renderimask |= RENDER_EXTERIORMODEL;
4074 memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4075 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4077 // worldmodel can check visibility
4078 for (i = 0;i < r_refdef.scene.numentities;i++)
4080 ent = r_refdef.scene.entities[i];
4081 if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4083 r_refdef.viewcache.entityvisible[i] = false;
4086 if (!(ent->flags & renderimask))
4087 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)))
4088 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))
4089 r_refdef.viewcache.entityvisible[i] = true;
4094 // no worldmodel or it can't check visibility
4095 for (i = 0;i < r_refdef.scene.numentities;i++)
4097 ent = r_refdef.scene.entities[i];
4098 if (!(ent->flags & renderimask))
4099 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)))
4100 r_refdef.viewcache.entityvisible[i] = true;
4103 if (r_cullentities_trace.integer)
4105 for (i = 0;i < r_refdef.scene.numentities;i++)
4107 if (!r_refdef.viewcache.entityvisible[i])
4109 ent = r_refdef.scene.entities[i];
4110 if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4112 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4113 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))
4114 ent->last_trace_visibility = host.realtime;
4115 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4116 r_refdef.viewcache.entityvisible[i] = 0;
4122 /// only used if skyrendermasked, and normally returns false
4123 static int R_DrawBrushModelsSky (void)
4126 entity_render_t *ent;
4129 for (i = 0;i < r_refdef.scene.numentities;i++)
4131 if (!r_refdef.viewcache.entityvisible[i])
4133 ent = r_refdef.scene.entities[i];
4134 if (!ent->model || !ent->model->DrawSky)
4136 ent->model->DrawSky(ent);
4142 static void R_DrawNoModel(entity_render_t *ent);
4143 static void R_DrawModels(void)
4146 entity_render_t *ent;
4148 for (i = 0;i < r_refdef.scene.numentities;i++)
4150 if (!r_refdef.viewcache.entityvisible[i])
4152 ent = r_refdef.scene.entities[i];
4153 r_refdef.stats[r_stat_entities]++;
4155 if (ent->model && ent->model->Draw != NULL)
4156 ent->model->Draw(ent);
4162 static void R_DrawModelsDepth(void)
4165 entity_render_t *ent;
4167 for (i = 0;i < r_refdef.scene.numentities;i++)
4169 if (!r_refdef.viewcache.entityvisible[i])
4171 ent = r_refdef.scene.entities[i];
4172 if (ent->model && ent->model->DrawDepth != NULL)
4173 ent->model->DrawDepth(ent);
4177 static void R_DrawModelsDebug(void)
4180 entity_render_t *ent;
4182 for (i = 0;i < r_refdef.scene.numentities;i++)
4184 if (!r_refdef.viewcache.entityvisible[i])
4186 ent = r_refdef.scene.entities[i];
4187 if (ent->model && ent->model->DrawDebug != NULL)
4188 ent->model->DrawDebug(ent);
4192 static void R_DrawModelsAddWaterPlanes(void)
4195 entity_render_t *ent;
4197 for (i = 0;i < r_refdef.scene.numentities;i++)
4199 if (!r_refdef.viewcache.entityvisible[i])
4201 ent = r_refdef.scene.entities[i];
4202 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4203 ent->model->DrawAddWaterPlanes(ent);
4207 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}};
4209 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4211 if (r_hdr_irisadaptation.integer)
4216 vec3_t diffusenormal;
4218 vec_t brightness = 0.0f;
4223 VectorCopy(r_refdef.view.forward, forward);
4224 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4226 p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4227 p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4228 p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4229 R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4230 d = DotProduct(forward, diffusenormal);
4231 brightness += VectorLength(ambient);
4233 brightness += d * VectorLength(diffuse);
4235 brightness *= 1.0f / c;
4236 brightness += 0.00001f; // make sure it's never zero
4237 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4238 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4239 current = r_hdr_irisadaptation_value.value;
4241 current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4242 else if (current > goal)
4243 current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4244 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4245 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4247 else if (r_hdr_irisadaptation_value.value != 1.0f)
4248 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4251 extern cvar_t r_lockvisibility;
4252 extern cvar_t r_lockpvs;
4254 static void R_View_SetFrustum(const int *scissor)
4257 double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4258 vec3_t forward, left, up, origin, v;
4259 if(r_lockvisibility.integer || r_lockpvs.integer)
4263 // flipped x coordinates (because x points left here)
4264 fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4265 fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4266 // non-flipped y coordinates
4267 fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4268 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4271 // we can't trust r_refdef.view.forward and friends in reflected scenes
4272 Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4275 r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4276 r_refdef.view.frustum[0].normal[1] = 0 - 0;
4277 r_refdef.view.frustum[0].normal[2] = -1 - 0;
4278 r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4279 r_refdef.view.frustum[1].normal[1] = 0 + 0;
4280 r_refdef.view.frustum[1].normal[2] = -1 + 0;
4281 r_refdef.view.frustum[2].normal[0] = 0 - 0;
4282 r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4283 r_refdef.view.frustum[2].normal[2] = -1 - 0;
4284 r_refdef.view.frustum[3].normal[0] = 0 + 0;
4285 r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4286 r_refdef.view.frustum[3].normal[2] = -1 + 0;
4290 zNear = r_refdef.nearclip;
4291 nudge = 1.0 - 1.0 / (1<<23);
4292 r_refdef.view.frustum[4].normal[0] = 0 - 0;
4293 r_refdef.view.frustum[4].normal[1] = 0 - 0;
4294 r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4295 r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4296 r_refdef.view.frustum[5].normal[0] = 0 + 0;
4297 r_refdef.view.frustum[5].normal[1] = 0 + 0;
4298 r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4299 r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4305 r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4306 r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4307 r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4308 r_refdef.view.frustum[0].dist = m[15] - m[12];
4310 r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4311 r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4312 r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4313 r_refdef.view.frustum[1].dist = m[15] + m[12];
4315 r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4316 r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4317 r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4318 r_refdef.view.frustum[2].dist = m[15] - m[13];
4320 r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4321 r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4322 r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4323 r_refdef.view.frustum[3].dist = m[15] + m[13];
4325 r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4326 r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4327 r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4328 r_refdef.view.frustum[4].dist = m[15] - m[14];
4330 r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4331 r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4332 r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4333 r_refdef.view.frustum[5].dist = m[15] + m[14];
4336 if (r_refdef.view.useperspective)
4338 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4339 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]);
4340 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]);
4341 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]);
4342 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]);
4344 // then the normals from the corners relative to origin
4345 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4346 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4347 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4348 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4350 // in a NORMAL view, forward cross left == up
4351 // in a REFLECTED view, forward cross left == down
4352 // so our cross products above need to be adjusted for a left handed coordinate system
4353 CrossProduct(forward, left, v);
4354 if(DotProduct(v, up) < 0)
4356 VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4357 VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4358 VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4359 VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4362 // Leaving those out was a mistake, those were in the old code, and they
4363 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4364 // I couldn't reproduce it after adding those normalizations. --blub
4365 VectorNormalize(r_refdef.view.frustum[0].normal);
4366 VectorNormalize(r_refdef.view.frustum[1].normal);
4367 VectorNormalize(r_refdef.view.frustum[2].normal);
4368 VectorNormalize(r_refdef.view.frustum[3].normal);
4370 // make the corners absolute
4371 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4372 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4373 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4374 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4377 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4379 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4380 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4381 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4382 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4383 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4387 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4388 VectorScale(left, 1.0f, r_refdef.view.frustum[1].normal);
4389 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4390 VectorScale(up, 1.0f, r_refdef.view.frustum[3].normal);
4391 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4392 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4393 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4394 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4395 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4396 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4398 r_refdef.view.numfrustumplanes = 5;
4400 if (r_refdef.view.useclipplane)
4402 r_refdef.view.numfrustumplanes = 6;
4403 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4406 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4407 PlaneClassify(r_refdef.view.frustum + i);
4409 // LadyHavoc: note to all quake engine coders, Quake had a special case
4410 // for 90 degrees which assumed a square view (wrong), so I removed it,
4411 // Quake2 has it disabled as well.
4413 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4414 //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4415 //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4416 //PlaneClassify(&frustum[0]);
4418 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4419 //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4420 //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4421 //PlaneClassify(&frustum[1]);
4423 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4424 //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4425 //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4426 //PlaneClassify(&frustum[2]);
4428 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4429 //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4430 //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4431 //PlaneClassify(&frustum[3]);
4434 //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4435 //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4436 //PlaneClassify(&frustum[4]);
4439 static void R_View_UpdateWithScissor(const int *myscissor)
4441 R_Main_ResizeViewCache();
4442 R_View_SetFrustum(myscissor);
4443 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4444 R_View_UpdateEntityVisible();
4447 static void R_View_Update(void)
4449 R_Main_ResizeViewCache();
4450 R_View_SetFrustum(NULL);
4451 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4452 R_View_UpdateEntityVisible();
4455 float viewscalefpsadjusted = 1.0f;
4457 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4459 const float *customclipplane = NULL;
4461 int /*rtwidth,*/ rtheight;
4462 if (r_refdef.view.useclipplane && allowwaterclippingplane)
4464 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4465 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4466 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4467 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4468 dist = r_refdef.view.clipplane.dist;
4469 plane[0] = r_refdef.view.clipplane.normal[0];
4470 plane[1] = r_refdef.view.clipplane.normal[1];
4471 plane[2] = r_refdef.view.clipplane.normal[2];
4473 customclipplane = plane;
4476 //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4477 rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4479 if (!r_refdef.view.useperspective)
4480 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);
4481 else if (vid.stencil && r_useinfinitefarclip.integer)
4482 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);
4484 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);
4485 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4486 R_SetViewport(&r_refdef.view.viewport);
4489 void R_EntityMatrix(const matrix4x4_t *matrix)
4491 if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4493 gl_modelmatrixchanged = false;
4494 gl_modelmatrix = *matrix;
4495 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4496 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4497 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4498 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4500 switch(vid.renderpath)
4502 case RENDERPATH_GL32:
4503 case RENDERPATH_GLES2:
4504 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4505 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4511 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4513 r_viewport_t viewport;
4517 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4518 R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4519 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4520 R_SetViewport(&viewport);
4521 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4522 GL_Color(1, 1, 1, 1);
4523 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4524 GL_BlendFunc(GL_ONE, GL_ZERO);
4525 GL_ScissorTest(false);
4526 GL_DepthMask(false);
4527 GL_DepthRange(0, 1);
4528 GL_DepthTest(false);
4529 GL_DepthFunc(GL_LEQUAL);
4530 R_EntityMatrix(&identitymatrix);
4531 R_Mesh_ResetTextureState();
4532 GL_PolygonOffset(0, 0);
4533 switch(vid.renderpath)
4535 case RENDERPATH_GL32:
4536 case RENDERPATH_GLES2:
4537 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4540 GL_CullFace(GL_NONE);
4545 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4547 R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4550 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4552 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4553 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4554 GL_Color(1, 1, 1, 1);
4555 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4556 GL_BlendFunc(GL_ONE, GL_ZERO);
4557 GL_ScissorTest(true);
4559 GL_DepthRange(0, 1);
4561 GL_DepthFunc(GL_LEQUAL);
4562 R_EntityMatrix(&identitymatrix);
4563 R_Mesh_ResetTextureState();
4564 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4565 switch(vid.renderpath)
4567 case RENDERPATH_GL32:
4568 case RENDERPATH_GLES2:
4569 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4572 GL_CullFace(r_refdef.view.cullface_back);
4577 R_RenderView_UpdateViewVectors
4580 void R_RenderView_UpdateViewVectors(void)
4582 // break apart the view matrix into vectors for various purposes
4583 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4584 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4585 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4586 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4587 // make an inverted copy of the view matrix for tracking sprites
4588 Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4591 void R_RenderTarget_FreeUnused(qbool force)
4593 unsigned int i, j, end;
4594 end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4595 for (i = 0; i < end; i++)
4597 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4598 // free resources for rendertargets that have not been used for a while
4599 // (note: this check is run after the frame render, so any targets used
4600 // this frame will not be affected even at low framerates)
4601 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4604 R_Mesh_DestroyFramebufferObject(r->fbo);
4605 for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4606 if (r->colortexture[j])
4607 R_FreeTexture(r->colortexture[j]);
4608 if (r->depthtexture)
4609 R_FreeTexture(r->depthtexture);
4610 Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4615 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4617 float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4621 y2 = (th - y - h) * ih;
4632 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qbool depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4634 unsigned int i, j, end;
4635 r_rendertarget_t *r = NULL;
4637 // first try to reuse an existing slot if possible
4638 end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4639 for (i = 0; i < end; i++)
4641 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4642 if (r && r->lastusetime != host.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)
4647 // no unused exact match found, so we have to make one in the first unused slot
4648 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4649 r->texturewidth = texturewidth;
4650 r->textureheight = textureheight;
4651 r->colortextype[0] = colortextype0;
4652 r->colortextype[1] = colortextype1;
4653 r->colortextype[2] = colortextype2;
4654 r->colortextype[3] = colortextype3;
4655 r->depthtextype = depthtextype;
4656 r->depthisrenderbuffer = depthisrenderbuffer;
4657 for (j = 0; j < 4; j++)
4658 if (r->colortextype[j])
4659 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);
4660 if (r->depthtextype)
4662 if (r->depthisrenderbuffer)
4663 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);
4665 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4667 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4669 r_refdef.stats[r_stat_rendertargets_used]++;
4670 r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4671 r->lastusetime = host.realtime;
4672 R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4676 static void R_Water_StartFrame(int viewwidth, int viewheight)
4678 int waterwidth, waterheight;
4680 if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4683 // set waterwidth and waterheight to the water resolution that will be
4684 // used (often less than the screen resolution for faster rendering)
4685 waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4686 waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4688 if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4689 waterwidth = waterheight = 0;
4691 // set up variables that will be used in shader setup
4692 r_fb.water.waterwidth = waterwidth;
4693 r_fb.water.waterheight = waterheight;
4694 r_fb.water.texturewidth = waterwidth;
4695 r_fb.water.textureheight = waterheight;
4696 r_fb.water.camerawidth = waterwidth;
4697 r_fb.water.cameraheight = waterheight;
4698 r_fb.water.screenscale[0] = 0.5f;
4699 r_fb.water.screenscale[1] = 0.5f;
4700 r_fb.water.screencenter[0] = 0.5f;
4701 r_fb.water.screencenter[1] = 0.5f;
4702 r_fb.water.enabled = waterwidth != 0;
4704 r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4705 r_fb.water.numwaterplanes = 0;
4708 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4710 int planeindex, bestplaneindex, vertexindex;
4711 vec3_t mins, maxs, normal, center, v, n;
4712 vec_t planescore, bestplanescore;
4714 r_waterstate_waterplane_t *p;
4715 texture_t *t = R_GetCurrentTexture(surface->texture);
4717 rsurface.texture = t;
4718 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4719 // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4720 if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4722 // average the vertex normals, find the surface bounds (after deformvertexes)
4723 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4724 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4725 VectorCopy(n, normal);
4726 VectorCopy(v, mins);
4727 VectorCopy(v, maxs);
4728 for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4730 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4731 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4732 VectorAdd(normal, n, normal);
4733 mins[0] = min(mins[0], v[0]);
4734 mins[1] = min(mins[1], v[1]);
4735 mins[2] = min(mins[2], v[2]);
4736 maxs[0] = max(maxs[0], v[0]);
4737 maxs[1] = max(maxs[1], v[1]);
4738 maxs[2] = max(maxs[2], v[2]);
4740 VectorNormalize(normal);
4741 VectorMAM(0.5f, mins, 0.5f, maxs, center);
4743 VectorCopy(normal, plane.normal);
4744 VectorNormalize(plane.normal);
4745 plane.dist = DotProduct(center, plane.normal);
4746 PlaneClassify(&plane);
4747 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4749 // skip backfaces (except if nocullface is set)
4750 // if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4752 VectorNegate(plane.normal, plane.normal);
4754 PlaneClassify(&plane);
4758 // find a matching plane if there is one
4759 bestplaneindex = -1;
4760 bestplanescore = 1048576.0f;
4761 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4763 if(p->camera_entity == t->camera_entity)
4765 planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4766 if (bestplaneindex < 0 || bestplanescore > planescore)
4768 bestplaneindex = planeindex;
4769 bestplanescore = planescore;
4773 planeindex = bestplaneindex;
4775 // if this surface does not fit any known plane rendered this frame, add one
4776 if (planeindex < 0 || bestplanescore > 0.001f)
4778 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4780 // store the new plane
4781 planeindex = r_fb.water.numwaterplanes++;
4782 p = r_fb.water.waterplanes + planeindex;
4784 // clear materialflags and pvs
4785 p->materialflags = 0;
4786 p->pvsvalid = false;
4787 p->camera_entity = t->camera_entity;
4788 VectorCopy(mins, p->mins);
4789 VectorCopy(maxs, p->maxs);
4793 // We're totally screwed.
4799 // merge mins/maxs when we're adding this surface to the plane
4800 p = r_fb.water.waterplanes + planeindex;
4801 p->mins[0] = min(p->mins[0], mins[0]);
4802 p->mins[1] = min(p->mins[1], mins[1]);
4803 p->mins[2] = min(p->mins[2], mins[2]);
4804 p->maxs[0] = max(p->maxs[0], maxs[0]);
4805 p->maxs[1] = max(p->maxs[1], maxs[1]);
4806 p->maxs[2] = max(p->maxs[2], maxs[2]);
4808 // merge this surface's materialflags into the waterplane
4809 p->materialflags |= t->currentmaterialflags;
4810 if(!(p->materialflags & MATERIALFLAG_CAMERA))
4812 // merge this surface's PVS into the waterplane
4813 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4814 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4816 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4822 extern cvar_t r_drawparticles;
4823 extern cvar_t r_drawdecals;
4825 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4828 r_refdef_view_t originalview;
4829 r_refdef_view_t myview;
4830 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;
4831 r_waterstate_waterplane_t *p;
4833 r_rendertarget_t *rt;
4835 originalview = r_refdef.view;
4837 // lowquality hack, temporarily shut down some cvars and restore afterwards
4838 qualityreduction = r_water_lowquality.integer;
4839 if (qualityreduction > 0)
4841 if (qualityreduction >= 1)
4843 old_r_shadows = r_shadows.integer;
4844 old_r_worldrtlight = r_shadow_realtime_world.integer;
4845 old_r_dlight = r_shadow_realtime_dlight.integer;
4846 Cvar_SetValueQuick(&r_shadows, 0);
4847 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4848 Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4850 if (qualityreduction >= 2)
4852 old_r_dynamic = r_dynamic.integer;
4853 old_r_particles = r_drawparticles.integer;
4854 old_r_decals = r_drawdecals.integer;
4855 Cvar_SetValueQuick(&r_dynamic, 0);
4856 Cvar_SetValueQuick(&r_drawparticles, 0);
4857 Cvar_SetValueQuick(&r_drawdecals, 0);
4861 for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4863 p->rt_reflection = NULL;
4864 p->rt_refraction = NULL;
4865 p->rt_camera = NULL;
4869 r_refdef.view = originalview;
4870 r_refdef.view.showdebug = false;
4871 r_refdef.view.width = r_fb.water.waterwidth;
4872 r_refdef.view.height = r_fb.water.waterheight;
4873 r_refdef.view.useclipplane = true;
4874 myview = r_refdef.view;
4875 r_fb.water.renderingscene = true;
4876 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4878 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4881 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4883 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);
4884 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4886 r_refdef.view = myview;
4887 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4888 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4889 if(r_water_scissormode.integer)
4891 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4892 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4894 p->rt_reflection = NULL;
4895 p->rt_refraction = NULL;
4896 p->rt_camera = NULL;
4901 r_refdef.view.clipplane = p->plane;
4902 // reflected view origin may be in solid, so don't cull with it
4903 r_refdef.view.usevieworiginculling = false;
4904 // reverse the cullface settings for this render
4905 r_refdef.view.cullface_front = GL_FRONT;
4906 r_refdef.view.cullface_back = GL_BACK;
4907 // combined pvs (based on what can be seen from each surface center)
4908 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4910 r_refdef.view.usecustompvs = true;
4912 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4914 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4917 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4918 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4919 GL_ScissorTest(false);
4920 R_ClearScreen(r_refdef.fogenabled);
4921 GL_ScissorTest(true);
4922 if(r_water_scissormode.integer & 2)
4923 R_View_UpdateWithScissor(myscissor);
4926 R_AnimCache_CacheVisibleEntities();
4927 if(r_water_scissormode.integer & 1)
4928 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4929 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4931 r_fb.water.hideplayer = false;
4932 p->rt_reflection = rt;
4935 // render the normal view scene and copy into texture
4936 // (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)
4937 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4939 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);
4940 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4942 r_refdef.view = myview;
4943 if(r_water_scissormode.integer)
4945 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4946 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4948 p->rt_reflection = NULL;
4949 p->rt_refraction = NULL;
4950 p->rt_camera = NULL;
4955 // combined pvs (based on what can be seen from each surface center)
4956 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4958 r_refdef.view.usecustompvs = true;
4960 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4962 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4965 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4967 r_refdef.view.clipplane = p->plane;
4968 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4969 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4971 if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4973 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4974 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4975 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4976 R_RenderView_UpdateViewVectors();
4977 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4979 r_refdef.view.usecustompvs = true;
4980 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);
4984 PlaneClassify(&r_refdef.view.clipplane);
4986 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4987 GL_ScissorTest(false);
4988 R_ClearScreen(r_refdef.fogenabled);
4989 GL_ScissorTest(true);
4990 if(r_water_scissormode.integer & 2)
4991 R_View_UpdateWithScissor(myscissor);
4994 R_AnimCache_CacheVisibleEntities();
4995 if(r_water_scissormode.integer & 1)
4996 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4997 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4999 r_fb.water.hideplayer = false;
5000 p->rt_refraction = rt;
5002 else if (p->materialflags & MATERIALFLAG_CAMERA)
5004 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);
5005 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5007 r_refdef.view = myview;
5009 r_refdef.view.clipplane = p->plane;
5010 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5011 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5013 r_refdef.view.width = r_fb.water.camerawidth;
5014 r_refdef.view.height = r_fb.water.cameraheight;
5015 r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5016 r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5017 r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5018 r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5020 if(p->camera_entity)
5022 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5023 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5026 // note: all of the view is used for displaying... so
5027 // there is no use in scissoring
5029 // reverse the cullface settings for this render
5030 r_refdef.view.cullface_front = GL_FRONT;
5031 r_refdef.view.cullface_back = GL_BACK;
5032 // also reverse the view matrix
5033 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
5034 R_RenderView_UpdateViewVectors();
5035 if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5037 r_refdef.view.usecustompvs = true;
5038 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
5041 // camera needs no clipplane
5042 r_refdef.view.useclipplane = false;
5043 // TODO: is the camera origin always valid? if so we don't need to clear this
5044 r_refdef.view.usevieworiginculling = false;
5046 PlaneClassify(&r_refdef.view.clipplane);
5048 r_fb.water.hideplayer = false;
5050 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5051 GL_ScissorTest(false);
5052 R_ClearScreen(r_refdef.fogenabled);
5053 GL_ScissorTest(true);
5055 R_AnimCache_CacheVisibleEntities();
5056 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5058 r_fb.water.hideplayer = false;
5063 r_fb.water.renderingscene = false;
5064 r_refdef.view = originalview;
5065 R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5067 R_AnimCache_CacheVisibleEntities();
5070 r_refdef.view = originalview;
5071 r_fb.water.renderingscene = false;
5072 Cvar_SetValueQuick(&r_water, 0);
5073 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
5075 // lowquality hack, restore cvars
5076 if (qualityreduction > 0)
5078 if (qualityreduction >= 1)
5080 Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5081 Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5082 Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5084 if (qualityreduction >= 2)
5086 Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5087 Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5088 Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5093 static void R_Bloom_StartFrame(void)
5095 int screentexturewidth, screentextureheight;
5096 textype_t textype = TEXTYPE_COLORBUFFER;
5099 // clear the pointers to rendertargets from last frame as they're stale
5100 r_fb.rt_screen = NULL;
5101 r_fb.rt_bloom = NULL;
5103 switch (vid.renderpath)
5105 case RENDERPATH_GL32:
5106 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5107 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5108 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5110 case RENDERPATH_GLES2:
5111 r_fb.usedepthtextures = false;
5115 if (r_viewscale_fpsscaling.integer)
5117 double actualframetime;
5118 double targetframetime;
5120 actualframetime = r_refdef.lastdrawscreentime;
5121 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5122 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5123 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5124 if (r_viewscale_fpsscaling_stepsize.value > 0)
5127 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5129 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5131 viewscalefpsadjusted += adjust;
5132 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5135 viewscalefpsadjusted = 1.0f;
5137 scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5139 scale *= sqrt(vid.samples); // supersampling
5140 scale = bound(0.03125f, scale, 4.0f);
5141 screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5142 screentextureheight = (int)ceil(r_refdef.view.height * scale);
5143 screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5144 screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5146 // set bloomwidth and bloomheight to the bloom resolution that will be
5147 // used (often less than the screen resolution for faster rendering)
5148 r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5149 r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5150 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5151 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5152 r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5154 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))
5156 Cvar_SetValueQuick(&r_bloom, 0);
5157 Cvar_SetValueQuick(&r_motionblur, 0);
5158 Cvar_SetValueQuick(&r_damageblur, 0);
5160 if (!r_bloom.integer)
5161 r_fb.bloomwidth = r_fb.bloomheight = 0;
5163 // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5164 if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5166 if (r_fb.ghosttexture)
5167 R_FreeTexture(r_fb.ghosttexture);
5168 r_fb.ghosttexture = NULL;
5170 r_fb.screentexturewidth = screentexturewidth;
5171 r_fb.screentextureheight = screentextureheight;
5172 r_fb.textype = textype;
5174 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5176 if (r_motionblur.value > 0 || r_damageblur.value > 0)
5177 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);
5178 r_fb.ghosttexture_valid = false;
5182 r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5184 r_refdef.view.clear = true;
5187 static void R_Bloom_MakeTexture(void)
5190 float xoffset, yoffset, r, brighten;
5191 float colorscale = r_bloom_colorscale.value;
5192 r_viewport_t bloomviewport;
5193 r_rendertarget_t *prev, *cur;
5194 textype_t textype = r_fb.rt_screen->colortextype[0];
5196 r_refdef.stats[r_stat_bloom]++;
5198 R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5200 // scale down screen texture to the bloom texture size
5202 prev = r_fb.rt_screen;
5203 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5204 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5205 R_SetViewport(&bloomviewport);
5206 GL_CullFace(GL_NONE);
5207 GL_DepthTest(false);
5208 GL_BlendFunc(GL_ONE, GL_ZERO);
5209 GL_Color(colorscale, colorscale, colorscale, 1);
5210 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5211 // TODO: do boxfilter scale-down in shader?
5212 R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5213 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5214 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5215 // we now have a properly scaled bloom image
5217 // multiply bloom image by itself as many times as desired to darken it
5218 // TODO: if people actually use this it could be done more quickly in the previous shader pass
5219 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5222 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5223 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5225 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5227 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5228 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5229 GL_Color(1,1,1,1); // no fix factor supported here
5230 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5231 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5232 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5233 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5237 range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5238 brighten = r_bloom_brighten.value;
5239 brighten = sqrt(brighten);
5241 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5243 for (dir = 0;dir < 2;dir++)
5246 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5247 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5248 // blend on at multiple vertical offsets to achieve a vertical blur
5249 // TODO: do offset blends using GLSL
5250 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5252 GL_BlendFunc(GL_ONE, GL_ZERO);
5254 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5256 for (x = -range;x <= range;x++)
5258 if (!dir){xoffset = 0;yoffset = x;}
5259 else {xoffset = x;yoffset = 0;}
5260 xoffset /= (float)prev->texturewidth;
5261 yoffset /= (float)prev->textureheight;
5262 // compute a texcoord array with the specified x and y offset
5263 r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5264 r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5265 r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5266 r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5267 r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5268 r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5269 r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5270 r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5271 // this r value looks like a 'dot' particle, fading sharply to
5272 // black at the edges
5273 // (probably not realistic but looks good enough)
5274 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5275 //r = brighten/(range*2+1);
5276 r = brighten / (range * 2 + 1);
5278 r *= (1 - x*x/(float)((range+1)*(range+1)));
5282 GL_Color(r, r, r, 1);
5284 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5286 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5287 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5289 GL_BlendFunc(GL_ONE, GL_ONE);
5294 // now we have the bloom image, so keep track of it
5295 r_fb.rt_bloom = cur;
5298 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5300 uint64_t permutation;
5301 float uservecs[4][4];
5302 rtexture_t *viewtexture;
5303 rtexture_t *bloomtexture;
5305 R_EntityMatrix(&identitymatrix);
5307 if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5309 // declare variables
5310 float blur_factor, blur_mouseaccel, blur_velocity;
5311 static float blur_average;
5312 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5314 // set a goal for the factoring
5315 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5316 / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5317 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5318 / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5319 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5320 + (blur_mouseaccel * r_motionblur_mousefactor.value));
5322 // from the goal, pick an averaged value between goal and last value
5323 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5324 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5326 // enforce minimum amount of blur
5327 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5329 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5331 // calculate values into a standard alpha
5332 cl.motionbluralpha = 1 - exp(-
5334 (r_motionblur.value * blur_factor / 80)
5336 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5339 max(0.0001, cl.time - cl.oldtime) // fps independent
5342 // randomization for the blur value to combat persistent ghosting
5343 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5344 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5347 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5348 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5350 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5351 GL_Color(1, 1, 1, cl.motionbluralpha);
5352 R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5353 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5354 R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5355 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5356 r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5359 // updates old view angles for next pass
5360 VectorCopy(cl.viewangles, blur_oldangles);
5362 // copy view into the ghost texture
5363 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5364 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5365 r_fb.ghosttexture_valid = true;
5368 if (r_fb.bloomwidth)
5370 // make the bloom texture
5371 R_Bloom_MakeTexture();
5374 #if _MSC_VER >= 1400
5375 #define sscanf sscanf_s
5377 memset(uservecs, 0, sizeof(uservecs));
5378 if (r_glsl_postprocess_uservec1_enable.integer)
5379 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5380 if (r_glsl_postprocess_uservec2_enable.integer)
5381 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5382 if (r_glsl_postprocess_uservec3_enable.integer)
5383 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5384 if (r_glsl_postprocess_uservec4_enable.integer)
5385 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5387 // render to the screen fbo
5388 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5389 GL_Color(1, 1, 1, 1);
5390 GL_BlendFunc(GL_ONE, GL_ZERO);
5392 viewtexture = r_fb.rt_screen->colortexture[0];
5393 bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5395 if (r_rendertarget_debug.integer >= 0)
5397 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5398 if (rt && rt->colortexture[0])
5400 viewtexture = rt->colortexture[0];
5401 bloomtexture = NULL;
5405 R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5406 switch(vid.renderpath)
5408 case RENDERPATH_GL32:
5409 case RENDERPATH_GLES2:
5411 (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5412 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5413 | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5414 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5415 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5416 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5417 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , viewtexture);
5418 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , bloomtexture);
5419 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps );
5420 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]);
5421 if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5422 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]);
5423 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]);
5424 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]);
5425 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]);
5426 if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value);
5427 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5428 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);
5429 if (r_glsl_permutation->loc_ColorFringe >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5432 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5433 r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5436 matrix4x4_t r_waterscrollmatrix;
5438 void R_UpdateFog(void)
5441 if (gamemode == GAME_NEHAHRA)
5443 if (gl_fogenable.integer)
5445 r_refdef.oldgl_fogenable = true;
5446 r_refdef.fog_density = gl_fogdensity.value;
5447 r_refdef.fog_red = gl_fogred.value;
5448 r_refdef.fog_green = gl_foggreen.value;
5449 r_refdef.fog_blue = gl_fogblue.value;
5450 r_refdef.fog_alpha = 1;
5451 r_refdef.fog_start = 0;
5452 r_refdef.fog_end = gl_skyclip.value;
5453 r_refdef.fog_height = 1<<30;
5454 r_refdef.fog_fadedepth = 128;
5456 else if (r_refdef.oldgl_fogenable)
5458 r_refdef.oldgl_fogenable = false;
5459 r_refdef.fog_density = 0;
5460 r_refdef.fog_red = 0;
5461 r_refdef.fog_green = 0;
5462 r_refdef.fog_blue = 0;
5463 r_refdef.fog_alpha = 0;
5464 r_refdef.fog_start = 0;
5465 r_refdef.fog_end = 0;
5466 r_refdef.fog_height = 1<<30;
5467 r_refdef.fog_fadedepth = 128;
5472 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5473 r_refdef.fog_start = max(0, r_refdef.fog_start);
5474 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5476 if (r_refdef.fog_density && r_drawfog.integer)
5478 r_refdef.fogenabled = true;
5479 // this is the point where the fog reaches 0.9986 alpha, which we
5480 // consider a good enough cutoff point for the texture
5481 // (0.9986 * 256 == 255.6)
5482 if (r_fog_exp2.integer)
5483 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5485 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5486 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5487 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5488 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5489 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5490 R_BuildFogHeightTexture();
5491 // fog color was already set
5492 // update the fog texture
5493 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)
5494 R_BuildFogTexture();
5495 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5496 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5499 r_refdef.fogenabled = false;
5502 if (r_refdef.fog_density)
5504 r_refdef.fogcolor[0] = r_refdef.fog_red;
5505 r_refdef.fogcolor[1] = r_refdef.fog_green;
5506 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5508 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5509 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5510 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5511 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5515 VectorCopy(r_refdef.fogcolor, fogvec);
5516 // color.rgb *= ContrastBoost * SceneBrightness;
5517 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5518 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5519 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5520 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5525 void R_UpdateVariables(void)
5529 r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5531 r_refdef.farclip = r_farclip_base.value;
5532 if (r_refdef.scene.worldmodel)
5533 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5534 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5536 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5537 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5538 r_refdef.polygonfactor = 0;
5539 r_refdef.polygonoffset = 0;
5541 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5542 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5543 r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5544 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5545 r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5546 if (r_refdef.scene.worldmodel)
5548 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5550 if (r_showsurfaces.integer)
5552 r_refdef.scene.rtworld = false;
5553 r_refdef.scene.rtworldshadows = false;
5554 r_refdef.scene.rtdlight = false;
5555 r_refdef.scene.rtdlightshadows = false;
5556 r_refdef.scene.lightmapintensity = 0;
5559 r_gpuskeletal = false;
5560 switch(vid.renderpath)
5562 case RENDERPATH_GL32:
5563 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5564 case RENDERPATH_GLES2:
5565 if(!vid_gammatables_trivial)
5567 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5569 // build GLSL gamma texture
5570 #define RAMPWIDTH 256
5571 unsigned short ramp[RAMPWIDTH * 3];
5572 unsigned char rampbgr[RAMPWIDTH][4];
5575 r_texture_gammaramps_serial = vid_gammatables_serial;
5577 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5578 for(i = 0; i < RAMPWIDTH; ++i)
5580 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5581 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5582 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5585 if (r_texture_gammaramps)
5587 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5591 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5597 // remove GLSL gamma texture
5603 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5604 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5610 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5611 if( scenetype != r_currentscenetype ) {
5612 // store the old scenetype
5613 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5614 r_currentscenetype = scenetype;
5615 // move in the new scene
5616 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5625 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5627 // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5628 if( scenetype == r_currentscenetype ) {
5629 return &r_refdef.scene;
5631 return &r_scenes_store[ scenetype ];
5635 static int R_SortEntities_Compare(const void *ap, const void *bp)
5637 const entity_render_t *a = *(const entity_render_t **)ap;
5638 const entity_render_t *b = *(const entity_render_t **)bp;
5641 if(a->model < b->model)
5643 if(a->model > b->model)
5647 // TODO possibly calculate the REAL skinnum here first using
5649 if(a->skinnum < b->skinnum)
5651 if(a->skinnum > b->skinnum)
5654 // everything we compared is equal
5657 static void R_SortEntities(void)
5659 // below or equal 2 ents, sorting never gains anything
5660 if(r_refdef.scene.numentities <= 2)
5663 qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5671 extern cvar_t r_shadow_bouncegrid;
5672 extern cvar_t v_isometric;
5673 extern void V_MakeViewIsometric(void);
5674 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5676 matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5678 rtexture_t *viewdepthtexture = NULL;
5679 rtexture_t *viewcolortexture = NULL;
5680 int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5682 // finish any 2D rendering that was queued
5685 if (r_timereport_active)
5686 R_TimeReport("start");
5687 r_textureframe++; // used only by R_GetCurrentTexture
5688 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5690 if(R_CompileShader_CheckStaticParms())
5691 R_GLSL_Restart_f(&cmd_client);
5693 if (!r_drawentities.integer)
5694 r_refdef.scene.numentities = 0;
5695 else if (r_sortentities.integer)
5698 R_AnimCache_ClearCache();
5700 /* adjust for stereo display */
5701 if(R_Stereo_Active())
5703 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);
5704 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5707 if (r_refdef.view.isoverlay)
5709 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5710 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5711 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5712 R_TimeReport("depthclear");
5714 r_refdef.view.showdebug = false;
5716 r_fb.water.enabled = false;
5717 r_fb.water.numwaterplanes = 0;
5719 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5721 r_refdef.view.matrix = originalmatrix;
5727 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5729 r_refdef.view.matrix = originalmatrix;
5733 r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5734 if (v_isometric.integer && r_refdef.view.ismain)
5735 V_MakeViewIsometric();
5737 r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5739 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5740 // in sRGB fallback, behave similar to true sRGB: convert this
5741 // value from linear to sRGB
5742 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5744 R_RenderView_UpdateViewVectors();
5746 R_Shadow_UpdateWorldLightSelection();
5748 // this will set up r_fb.rt_screen
5749 R_Bloom_StartFrame();
5751 // apply bloom brightness offset
5753 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5755 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5758 viewfbo = r_fb.rt_screen->fbo;
5759 viewdepthtexture = r_fb.rt_screen->depthtexture;
5760 viewcolortexture = r_fb.rt_screen->colortexture[0];
5763 viewwidth = r_fb.rt_screen->texturewidth;
5764 viewheight = r_fb.rt_screen->textureheight;
5767 R_Water_StartFrame(viewwidth, viewheight);
5770 if (r_timereport_active)
5771 R_TimeReport("viewsetup");
5773 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5775 // clear the whole fbo every frame - otherwise the driver will consider
5776 // it to be an inter-frame texture and stall in multi-gpu configurations
5778 GL_ScissorTest(false);
5779 R_ClearScreen(r_refdef.fogenabled);
5780 if (r_timereport_active)
5781 R_TimeReport("viewclear");
5783 r_refdef.view.clear = true;
5785 r_refdef.view.showdebug = true;
5788 if (r_timereport_active)
5789 R_TimeReport("visibility");
5791 R_AnimCache_CacheVisibleEntities();
5792 if (r_timereport_active)
5793 R_TimeReport("animcache");
5795 R_Shadow_UpdateBounceGridTexture();
5796 // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5798 r_fb.water.numwaterplanes = 0;
5799 if (r_fb.water.enabled)
5800 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5802 // for the actual view render we use scissoring a fair amount, so scissor
5803 // test needs to be on
5805 GL_ScissorTest(true);
5806 GL_Scissor(viewx, viewy, viewwidth, viewheight);
5807 R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5808 r_fb.water.numwaterplanes = 0;
5810 // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5811 GL_ScissorTest(false);
5813 R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5814 if (r_timereport_active)
5815 R_TimeReport("blendview");
5817 r_refdef.view.matrix = originalmatrix;
5821 // go back to 2d rendering
5825 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5827 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5829 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5830 if (r_timereport_active)
5831 R_TimeReport("waterworld");
5834 // don't let sound skip if going slow
5835 if (r_refdef.scene.extraupdate)
5838 R_DrawModelsAddWaterPlanes();
5839 if (r_timereport_active)
5840 R_TimeReport("watermodels");
5842 if (r_fb.water.numwaterplanes)
5844 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5845 if (r_timereport_active)
5846 R_TimeReport("waterscenes");
5850 extern cvar_t cl_locs_show;
5851 static void R_DrawLocs(void);
5852 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5853 static void R_DrawModelDecals(void);
5854 extern qbool r_shadow_usingdeferredprepass;
5855 extern int r_shadow_shadowmapatlas_modelshadows_size;
5856 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5858 qbool shadowmapping = false;
5860 if (r_timereport_active)
5861 R_TimeReport("beginscene");
5863 r_refdef.stats[r_stat_renders]++;
5867 // don't let sound skip if going slow
5868 if (r_refdef.scene.extraupdate)
5871 R_MeshQueue_BeginScene();
5875 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);
5877 if (r_timereport_active)
5878 R_TimeReport("skystartframe");
5880 if (cl.csqc_vidvars.drawworld)
5882 // don't let sound skip if going slow
5883 if (r_refdef.scene.extraupdate)
5886 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5888 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5889 if (r_timereport_active)
5890 R_TimeReport("worldsky");
5893 if (R_DrawBrushModelsSky() && r_timereport_active)
5894 R_TimeReport("bmodelsky");
5896 if (skyrendermasked && skyrenderlater)
5898 // we have to force off the water clipping plane while rendering sky
5899 R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5901 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5902 if (r_timereport_active)
5903 R_TimeReport("sky");
5907 // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5908 r_shadow_viewfbo = viewfbo;
5909 r_shadow_viewdepthtexture = viewdepthtexture;
5910 r_shadow_viewcolortexture = viewcolortexture;
5911 r_shadow_viewx = viewx;
5912 r_shadow_viewy = viewy;
5913 r_shadow_viewwidth = viewwidth;
5914 r_shadow_viewheight = viewheight;
5916 R_Shadow_PrepareModelShadows();
5917 R_Shadow_PrepareLights();
5918 if (r_timereport_active)
5919 R_TimeReport("preparelights");
5921 // render all the shadowmaps that will be used for this view
5922 shadowmapping = R_Shadow_ShadowMappingEnabled();
5923 if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5925 R_Shadow_DrawShadowMaps();
5926 if (r_timereport_active)
5927 R_TimeReport("shadowmaps");
5930 // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5931 if (r_shadow_usingdeferredprepass)
5932 R_Shadow_DrawPrepass();
5934 // now we begin the forward pass of the view render
5935 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5937 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5938 if (r_timereport_active)
5939 R_TimeReport("worlddepth");
5941 if (r_depthfirst.integer >= 2)
5943 R_DrawModelsDepth();
5944 if (r_timereport_active)
5945 R_TimeReport("modeldepth");
5948 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5950 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5951 if (r_timereport_active)
5952 R_TimeReport("world");
5955 // don't let sound skip if going slow
5956 if (r_refdef.scene.extraupdate)
5960 if (r_timereport_active)
5961 R_TimeReport("models");
5963 // don't let sound skip if going slow
5964 if (r_refdef.scene.extraupdate)
5967 if (!r_shadow_usingdeferredprepass)
5969 R_Shadow_DrawLights();
5970 if (r_timereport_active)
5971 R_TimeReport("rtlights");
5974 // don't let sound skip if going slow
5975 if (r_refdef.scene.extraupdate)
5978 if (cl.csqc_vidvars.drawworld)
5980 R_DrawModelDecals();
5981 if (r_timereport_active)
5982 R_TimeReport("modeldecals");
5985 if (r_timereport_active)
5986 R_TimeReport("particles");
5989 if (r_timereport_active)
5990 R_TimeReport("explosions");
5993 if (r_refdef.view.showdebug)
5995 if (cl_locs_show.integer)
5998 if (r_timereport_active)
5999 R_TimeReport("showlocs");
6002 if (r_drawportals.integer)
6005 if (r_timereport_active)
6006 R_TimeReport("portals");
6009 if (r_showbboxes_client.value > 0)
6011 R_DrawEntityBBoxes(CLVM_prog);
6012 if (r_timereport_active)
6013 R_TimeReport("clbboxes");
6015 if (r_showbboxes.value > 0)
6017 R_DrawEntityBBoxes(SVVM_prog);
6018 if (r_timereport_active)
6019 R_TimeReport("svbboxes");
6023 if (r_transparent.integer)
6025 R_MeshQueue_RenderTransparent();
6026 if (r_timereport_active)
6027 R_TimeReport("drawtrans");
6030 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))
6032 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6033 if (r_timereport_active)
6034 R_TimeReport("worlddebug");
6035 R_DrawModelsDebug();
6036 if (r_timereport_active)
6037 R_TimeReport("modeldebug");
6040 if (cl.csqc_vidvars.drawworld)
6042 R_Shadow_DrawCoronas();
6043 if (r_timereport_active)
6044 R_TimeReport("coronas");
6047 // don't let sound skip if going slow
6048 if (r_refdef.scene.extraupdate)
6052 static const unsigned short bboxelements[36] =
6062 #define BBOXEDGES 13
6063 static const float bboxedges[BBOXEDGES][6] =
6066 { 0, 0, 0, 1, 1, 1 },
6068 { 0, 0, 0, 0, 1, 0 },
6069 { 0, 0, 0, 1, 0, 0 },
6070 { 0, 1, 0, 1, 1, 0 },
6071 { 1, 0, 0, 1, 1, 0 },
6073 { 0, 0, 1, 0, 1, 1 },
6074 { 0, 0, 1, 1, 0, 1 },
6075 { 0, 1, 1, 1, 1, 1 },
6076 { 1, 0, 1, 1, 1, 1 },
6078 { 0, 0, 0, 0, 0, 1 },
6079 { 1, 0, 0, 1, 0, 1 },
6080 { 0, 1, 0, 0, 1, 1 },
6081 { 1, 1, 0, 1, 1, 1 },
6084 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6086 int numvertices = BBOXEDGES * 8;
6087 float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6088 int numtriangles = BBOXEDGES * 12;
6089 unsigned short elements[BBOXEDGES * 36];
6091 float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6093 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6095 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6096 GL_DepthMask(false);
6097 GL_DepthRange(0, 1);
6098 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6100 for (edge = 0; edge < BBOXEDGES; edge++)
6102 for (i = 0; i < 3; i++)
6104 edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6105 edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6107 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6108 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6109 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6110 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6111 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6112 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6113 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6114 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6115 for (i = 0; i < 36; i++)
6116 elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6118 R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6119 if (r_refdef.fogenabled)
6121 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6123 f1 = RSurf_FogVertex(v);
6125 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6126 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6127 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6130 R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6131 R_Mesh_ResetTextureState();
6132 R_SetupShader_Generic_NoTexture(false, false);
6133 R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6136 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6138 // hacky overloading of the parameters
6139 prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6142 prvm_edict_t *edict;
6144 GL_CullFace(GL_NONE);
6145 R_SetupShader_Generic_NoTexture(false, false);
6147 for (i = 0;i < numsurfaces;i++)
6149 edict = PRVM_EDICT_NUM(surfacelist[i]);
6150 switch ((int)PRVM_serveredictfloat(edict, solid))
6152 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
6153 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
6154 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
6155 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6156 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
6157 case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break;
6158 default: Vector4Set(color, 0, 0, 0, 0.50);break;
6160 if (prog == CLVM_prog)
6161 color[3] *= r_showbboxes_client.value;
6163 color[3] *= r_showbboxes.value;
6164 color[3] = bound(0, color[3], 1);
6165 GL_DepthTest(!r_showdisabledepthtest.integer);
6166 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6170 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6173 prvm_edict_t *edict;
6179 for (i = 0; i < prog->num_edicts; i++)
6181 edict = PRVM_EDICT_NUM(i);
6182 if (edict->priv.server->free)
6184 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6185 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6187 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6189 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6190 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6194 static const int nomodelelement3i[24] =
6206 static const unsigned short nomodelelement3s[24] =
6218 static const float nomodelvertex3f[6*3] =
6228 static const float nomodelcolor4f[6*4] =
6230 0.0f, 0.0f, 0.5f, 1.0f,
6231 0.0f, 0.0f, 0.5f, 1.0f,
6232 0.0f, 0.5f, 0.0f, 1.0f,
6233 0.0f, 0.5f, 0.0f, 1.0f,
6234 0.5f, 0.0f, 0.0f, 1.0f,
6235 0.5f, 0.0f, 0.0f, 1.0f
6238 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6244 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);
6246 // this is only called once per entity so numsurfaces is always 1, and
6247 // surfacelist is always {0}, so this code does not handle batches
6249 if (rsurface.ent_flags & RENDER_ADDITIVE)
6251 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6252 GL_DepthMask(false);
6254 else if (ent->alpha < 1)
6256 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6257 GL_DepthMask(false);
6261 GL_BlendFunc(GL_ONE, GL_ZERO);
6264 GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6265 GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6266 GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6267 GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6268 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6269 for (i = 0, c = color4f;i < 6;i++, c += 4)
6271 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6272 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6273 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6276 if (r_refdef.fogenabled)
6278 for (i = 0, c = color4f;i < 6;i++, c += 4)
6280 f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6282 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6283 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6284 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6287 // R_Mesh_ResetTextureState();
6288 R_SetupShader_Generic_NoTexture(false, false);
6289 R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6290 R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6293 void R_DrawNoModel(entity_render_t *ent)
6296 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6297 if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6298 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6300 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6303 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6305 vec3_t right1, right2, diff, normal;
6307 VectorSubtract (org2, org1, normal);
6309 // calculate 'right' vector for start
6310 VectorSubtract (r_refdef.view.origin, org1, diff);
6311 CrossProduct (normal, diff, right1);
6312 VectorNormalize (right1);
6314 // calculate 'right' vector for end
6315 VectorSubtract (r_refdef.view.origin, org2, diff);
6316 CrossProduct (normal, diff, right2);
6317 VectorNormalize (right2);
6319 vert[ 0] = org1[0] + width * right1[0];
6320 vert[ 1] = org1[1] + width * right1[1];
6321 vert[ 2] = org1[2] + width * right1[2];
6322 vert[ 3] = org1[0] - width * right1[0];
6323 vert[ 4] = org1[1] - width * right1[1];
6324 vert[ 5] = org1[2] - width * right1[2];
6325 vert[ 6] = org2[0] - width * right2[0];
6326 vert[ 7] = org2[1] - width * right2[1];
6327 vert[ 8] = org2[2] - width * right2[2];
6328 vert[ 9] = org2[0] + width * right2[0];
6329 vert[10] = org2[1] + width * right2[1];
6330 vert[11] = org2[2] + width * right2[2];
6333 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)
6335 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6336 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6337 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6338 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6339 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6340 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6341 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6342 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6343 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6344 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6345 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6346 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6349 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6354 VectorSet(v, x, y, z);
6355 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6356 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6358 if (i == mesh->numvertices)
6360 if (mesh->numvertices < mesh->maxvertices)
6362 VectorCopy(v, vertex3f);
6363 mesh->numvertices++;
6365 return mesh->numvertices;
6371 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6375 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6376 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6377 e = mesh->element3i + mesh->numtriangles * 3;
6378 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6380 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6381 if (mesh->numtriangles < mesh->maxtriangles)
6386 mesh->numtriangles++;
6388 element[1] = element[2];
6392 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6396 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6397 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6398 e = mesh->element3i + mesh->numtriangles * 3;
6399 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6401 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6402 if (mesh->numtriangles < mesh->maxtriangles)
6407 mesh->numtriangles++;
6409 element[1] = element[2];
6413 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6414 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6416 int planenum, planenum2;
6419 mplane_t *plane, *plane2;
6421 double temppoints[2][256*3];
6422 // figure out how large a bounding box we need to properly compute this brush
6424 for (w = 0;w < numplanes;w++)
6425 maxdist = max(maxdist, fabs(planes[w].dist));
6426 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6427 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6428 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6432 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6433 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6435 if (planenum2 == planenum)
6437 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);
6440 if (tempnumpoints < 3)
6442 // generate elements forming a triangle fan for this polygon
6443 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6447 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6449 if(parms[0] == 0 && parms[1] == 0)
6451 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6452 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6457 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6460 index = parms[2] + rsurface.shadertime * parms[3];
6461 index -= floor(index);
6462 switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6465 case Q3WAVEFUNC_NONE:
6466 case Q3WAVEFUNC_NOISE:
6467 case Q3WAVEFUNC_COUNT:
6470 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6471 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6472 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6473 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6474 case Q3WAVEFUNC_TRIANGLE:
6476 f = index - floor(index);
6489 f = parms[0] + parms[1] * f;
6490 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6491 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6495 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6502 matrix4x4_t matrix, temp;
6503 // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6504 // it's better to have one huge fixup every 9 hours than gradual
6505 // degradation over time which looks consistently bad after many hours.
6507 // tcmod scroll in particular suffers from this degradation which can't be
6508 // effectively worked around even with floor() tricks because we don't
6509 // know if tcmod scroll is the last tcmod being applied, and for clampmap
6510 // a workaround involving floor() would be incorrect anyway...
6511 shadertime = rsurface.shadertime;
6512 if (shadertime >= 32768.0f)
6513 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6514 switch(tcmod->tcmod)
6518 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6519 matrix = r_waterscrollmatrix;
6521 matrix = identitymatrix;
6523 case Q3TCMOD_ENTITYTRANSLATE:
6524 // this is used in Q3 to allow the gamecode to control texcoord
6525 // scrolling on the entity, which is not supported in darkplaces yet.
6526 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6528 case Q3TCMOD_ROTATE:
6529 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6530 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6531 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6534 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6536 case Q3TCMOD_SCROLL:
6537 // this particular tcmod is a "bug for bug" compatible one with regards to
6538 // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6539 // specifically did the wrapping and so we must mimic that...
6540 offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6541 offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6542 Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6544 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6545 w = (int) tcmod->parms[0];
6546 h = (int) tcmod->parms[1];
6547 f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6549 idx = (int) floor(f * w * h);
6550 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6552 case Q3TCMOD_STRETCH:
6553 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6554 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6556 case Q3TCMOD_TRANSFORM:
6557 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
6558 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
6559 VectorSet(tcmat + 6, 0 , 0 , 1);
6560 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
6561 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6563 case Q3TCMOD_TURBULENT:
6564 // this is handled in the RSurf_PrepareVertices function
6565 matrix = identitymatrix;
6569 Matrix4x4_Concat(texmatrix, &matrix, &temp);
6572 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6574 int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6575 char name[MAX_QPATH];
6576 skinframe_t *skinframe;
6577 unsigned char pixels[296*194];
6578 strlcpy(cache->name, skinname, sizeof(cache->name));
6579 dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6580 if (developer_loading.integer)
6581 Con_Printf("loading %s\n", name);
6582 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6583 if (!skinframe || !skinframe->base)
6586 fs_offset_t filesize;
6588 f = FS_LoadFile(name, tempmempool, true, &filesize);
6591 if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6592 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6596 cache->skinframe = skinframe;
6599 texture_t *R_GetCurrentTexture(texture_t *t)
6602 const entity_render_t *ent = rsurface.entity;
6603 model_t *model = ent->model; // when calling this, ent must not be NULL
6604 q3shaderinfo_layer_tcmod_t *tcmod;
6605 float specularscale = 0.0f;
6607 if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6608 return t->currentframe;
6609 t->update_lastrenderframe = r_textureframe;
6610 t->update_lastrenderentity = (void *)ent;
6612 if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6613 t->camera_entity = ent->entitynumber;
6615 t->camera_entity = 0;
6617 // switch to an alternate material if this is a q1bsp animated material
6619 texture_t *texture = t;
6620 int s = rsurface.ent_skinnum;
6621 if ((unsigned int)s >= (unsigned int)model->numskins)
6623 if (model->skinscenes)
6625 if (model->skinscenes[s].framecount > 1)
6626 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6628 s = model->skinscenes[s].firstframe;
6631 t = t + s * model->num_surfaces;
6634 // use an alternate animation if the entity's frame is not 0,
6635 // and only if the texture has an alternate animation
6636 if (t->animated == 2) // q2bsp
6637 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6638 else if (rsurface.ent_alttextures && t->anim_total[1])
6639 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6641 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6643 texture->currentframe = t;
6646 // update currentskinframe to be a qw skin or animation frame
6647 if (rsurface.ent_qwskin >= 0)
6649 i = rsurface.ent_qwskin;
6650 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6652 r_qwskincache_size = cl.maxclients;
6654 Mem_Free(r_qwskincache);
6655 r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6657 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6658 R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6659 t->currentskinframe = r_qwskincache[i].skinframe;
6660 if (t->materialshaderpass && t->currentskinframe == NULL)
6661 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6663 else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6664 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6665 if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6666 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6668 t->currentmaterialflags = t->basematerialflags;
6669 t->currentalpha = rsurface.entity->alpha * t->basealpha;
6670 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6671 t->currentalpha *= r_wateralpha.value;
6672 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6673 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6674 if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6675 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6677 // decide on which type of lighting to use for this surface
6678 if (rsurface.entity->render_modellight_forced)
6679 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6680 if (rsurface.entity->render_rtlight_disabled)
6681 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6682 if (rsurface.entity->render_lightgrid)
6683 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6684 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6686 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6687 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6688 for (q = 0; q < 3; q++)
6690 t->render_glowmod[q] = rsurface.entity->glowmod[q];
6691 t->render_modellight_lightdir_world[q] = q == 2;
6692 t->render_modellight_lightdir_local[q] = q == 2;
6693 t->render_modellight_ambient[q] = 1;
6694 t->render_modellight_diffuse[q] = 0;
6695 t->render_modellight_specular[q] = 0;
6696 t->render_lightmap_ambient[q] = 0;
6697 t->render_lightmap_diffuse[q] = 0;
6698 t->render_lightmap_specular[q] = 0;
6699 t->render_rtlight_diffuse[q] = 0;
6700 t->render_rtlight_specular[q] = 0;
6703 else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6705 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6706 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6707 for (q = 0; q < 3; q++)
6709 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6710 t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6711 t->render_modellight_lightdir_world[q] = q == 2;
6712 t->render_modellight_lightdir_local[q] = q == 2;
6713 t->render_modellight_diffuse[q] = 0;
6714 t->render_modellight_specular[q] = 0;
6715 t->render_lightmap_ambient[q] = 0;
6716 t->render_lightmap_diffuse[q] = 0;
6717 t->render_lightmap_specular[q] = 0;
6718 t->render_rtlight_diffuse[q] = 0;
6719 t->render_rtlight_specular[q] = 0;
6722 else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6724 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6725 for (q = 0; q < 3; q++)
6727 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6728 t->render_modellight_lightdir_world[q] = q == 2;
6729 t->render_modellight_lightdir_local[q] = q == 2;
6730 t->render_modellight_ambient[q] = 0;
6731 t->render_modellight_diffuse[q] = 0;
6732 t->render_modellight_specular[q] = 0;
6733 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6734 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6735 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6736 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6737 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6740 else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6742 // ambient + single direction light (modellight)
6743 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6744 for (q = 0; q < 3; q++)
6746 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6747 t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6748 t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6749 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6750 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6751 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6752 t->render_lightmap_ambient[q] = 0;
6753 t->render_lightmap_diffuse[q] = 0;
6754 t->render_lightmap_specular[q] = 0;
6755 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6756 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6761 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6762 for (q = 0; q < 3; q++)
6764 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6765 t->render_modellight_lightdir_world[q] = q == 2;
6766 t->render_modellight_lightdir_local[q] = q == 2;
6767 t->render_modellight_ambient[q] = 0;
6768 t->render_modellight_diffuse[q] = 0;
6769 t->render_modellight_specular[q] = 0;
6770 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6771 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6772 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6773 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6774 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6778 if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6780 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6781 // attribute, we punt it to the lightmap path and hope for the best,
6782 // but lighting doesn't work.
6784 // FIXME: this is fine for effects but CSQC polygons should be subject
6786 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6787 for (q = 0; q < 3; q++)
6789 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6790 t->render_modellight_lightdir_world[q] = q == 2;
6791 t->render_modellight_lightdir_local[q] = q == 2;
6792 t->render_modellight_ambient[q] = 0;
6793 t->render_modellight_diffuse[q] = 0;
6794 t->render_modellight_specular[q] = 0;
6795 t->render_lightmap_ambient[q] = 0;
6796 t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6797 t->render_lightmap_specular[q] = 0;
6798 t->render_rtlight_diffuse[q] = 0;
6799 t->render_rtlight_specular[q] = 0;
6803 for (q = 0; q < 3; q++)
6805 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6806 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6809 if (rsurface.ent_flags & RENDER_ADDITIVE)
6810 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6811 else if (t->currentalpha < 1)
6812 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6813 // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6814 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6815 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6816 if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6817 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6818 if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6819 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6820 if (t->backgroundshaderpass)
6821 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6822 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6824 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6825 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6828 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6829 if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6831 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6832 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6834 if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6835 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6837 // there is no tcmod
6838 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6840 t->currenttexmatrix = r_waterscrollmatrix;
6841 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6843 else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6845 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6846 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6849 if (t->materialshaderpass)
6850 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6851 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6853 t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6854 if (t->currentskinframe->qpixels)
6855 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6856 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6857 if (!t->basetexture)
6858 t->basetexture = r_texture_notexture;
6859 t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6860 t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6861 t->nmaptexture = t->currentskinframe->nmap;
6862 if (!t->nmaptexture)
6863 t->nmaptexture = r_texture_blanknormalmap;
6864 t->glosstexture = r_texture_black;
6865 t->glowtexture = t->currentskinframe->glow;
6866 t->fogtexture = t->currentskinframe->fog;
6867 t->reflectmasktexture = t->currentskinframe->reflect;
6868 if (t->backgroundshaderpass)
6870 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6871 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6872 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6873 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6874 t->backgroundglosstexture = r_texture_black;
6875 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6876 if (!t->backgroundnmaptexture)
6877 t->backgroundnmaptexture = r_texture_blanknormalmap;
6878 // make sure that if glow is going to be used, both textures are not NULL
6879 if (!t->backgroundglowtexture && t->glowtexture)
6880 t->backgroundglowtexture = r_texture_black;
6881 if (!t->glowtexture && t->backgroundglowtexture)
6882 t->glowtexture = r_texture_black;
6886 t->backgroundbasetexture = r_texture_white;
6887 t->backgroundnmaptexture = r_texture_blanknormalmap;
6888 t->backgroundglosstexture = r_texture_black;
6889 t->backgroundglowtexture = NULL;
6891 t->specularpower = r_shadow_glossexponent.value;
6892 // TODO: store reference values for these in the texture?
6893 if (r_shadow_gloss.integer > 0)
6895 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6897 if (r_shadow_glossintensity.value > 0)
6899 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6900 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6901 specularscale = r_shadow_glossintensity.value;
6904 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6906 t->glosstexture = r_texture_white;
6907 t->backgroundglosstexture = r_texture_white;
6908 specularscale = r_shadow_gloss2intensity.value;
6909 t->specularpower = r_shadow_gloss2exponent.value;
6912 specularscale *= t->specularscalemod;
6913 t->specularpower *= t->specularpowermod;
6915 // lightmaps mode looks bad with dlights using actual texturing, so turn
6916 // off the colormap and glossmap, but leave the normalmap on as it still
6917 // accurately represents the shading involved
6918 if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6920 t->basetexture = r_texture_grey128;
6921 t->pantstexture = r_texture_black;
6922 t->shirttexture = r_texture_black;
6923 if (gl_lightmaps.integer < 2)
6924 t->nmaptexture = r_texture_blanknormalmap;
6925 t->glosstexture = r_texture_black;
6926 t->glowtexture = NULL;
6927 t->fogtexture = NULL;
6928 t->reflectmasktexture = NULL;
6929 t->backgroundbasetexture = NULL;
6930 if (gl_lightmaps.integer < 2)
6931 t->backgroundnmaptexture = r_texture_blanknormalmap;
6932 t->backgroundglosstexture = r_texture_black;
6933 t->backgroundglowtexture = NULL;
6935 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6938 if (specularscale != 1.0f)
6940 for (q = 0; q < 3; q++)
6942 t->render_modellight_specular[q] *= specularscale;
6943 t->render_lightmap_specular[q] *= specularscale;
6944 t->render_rtlight_specular[q] *= specularscale;
6948 t->currentblendfunc[0] = GL_ONE;
6949 t->currentblendfunc[1] = GL_ZERO;
6950 if (t->currentmaterialflags & MATERIALFLAG_ADD)
6952 t->currentblendfunc[0] = GL_SRC_ALPHA;
6953 t->currentblendfunc[1] = GL_ONE;
6955 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6957 t->currentblendfunc[0] = GL_SRC_ALPHA;
6958 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6960 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6962 t->currentblendfunc[0] = t->customblendfunc[0];
6963 t->currentblendfunc[1] = t->customblendfunc[1];
6969 rsurfacestate_t rsurface;
6971 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6973 model_t *model = ent->model;
6974 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6976 rsurface.entity = (entity_render_t *)ent;
6977 rsurface.skeleton = ent->skeleton;
6978 memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6979 rsurface.ent_skinnum = ent->skinnum;
6980 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;
6981 rsurface.ent_flags = ent->flags;
6982 if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6983 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6984 rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6985 rsurface.matrix = ent->matrix;
6986 rsurface.inversematrix = ent->inversematrix;
6987 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6988 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6989 R_EntityMatrix(&rsurface.matrix);
6990 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6991 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6992 rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6993 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6994 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6995 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6996 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6997 rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6998 rsurface.basepolygonfactor = r_refdef.polygonfactor;
6999 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7000 if (ent->model->brush.submodel && !prepass)
7002 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7003 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7005 // if the animcache code decided it should use the shader path, skip the deform step
7006 rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7007 rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7008 rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7009 rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7010 rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7011 if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7013 if (ent->animcache_vertex3f)
7015 r_refdef.stats[r_stat_batch_entitycache_count]++;
7016 r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7017 r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7018 r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7019 rsurface.modelvertex3f = ent->animcache_vertex3f;
7020 rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7021 rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7022 rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7023 rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7024 rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7025 rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7026 rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7027 rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7028 rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7029 rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7030 rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7032 else if (wanttangents)
7034 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7035 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7036 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7037 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7038 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7039 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7040 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7041 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7042 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7043 rsurface.modelvertex3f_vertexbuffer = NULL;
7044 rsurface.modelvertex3f_bufferoffset = 0;
7045 rsurface.modelvertex3f_vertexbuffer = 0;
7046 rsurface.modelvertex3f_bufferoffset = 0;
7047 rsurface.modelsvector3f_vertexbuffer = 0;
7048 rsurface.modelsvector3f_bufferoffset = 0;
7049 rsurface.modeltvector3f_vertexbuffer = 0;
7050 rsurface.modeltvector3f_bufferoffset = 0;
7051 rsurface.modelnormal3f_vertexbuffer = 0;
7052 rsurface.modelnormal3f_bufferoffset = 0;
7054 else if (wantnormals)
7056 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7057 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7058 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7059 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7060 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7061 rsurface.modelsvector3f = NULL;
7062 rsurface.modeltvector3f = NULL;
7063 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7064 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7065 rsurface.modelvertex3f_vertexbuffer = NULL;
7066 rsurface.modelvertex3f_bufferoffset = 0;
7067 rsurface.modelvertex3f_vertexbuffer = 0;
7068 rsurface.modelvertex3f_bufferoffset = 0;
7069 rsurface.modelsvector3f_vertexbuffer = 0;
7070 rsurface.modelsvector3f_bufferoffset = 0;
7071 rsurface.modeltvector3f_vertexbuffer = 0;
7072 rsurface.modeltvector3f_bufferoffset = 0;
7073 rsurface.modelnormal3f_vertexbuffer = 0;
7074 rsurface.modelnormal3f_bufferoffset = 0;
7078 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7079 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7080 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7081 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7082 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7083 rsurface.modelsvector3f = NULL;
7084 rsurface.modeltvector3f = NULL;
7085 rsurface.modelnormal3f = NULL;
7086 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7087 rsurface.modelvertex3f_vertexbuffer = NULL;
7088 rsurface.modelvertex3f_bufferoffset = 0;
7089 rsurface.modelvertex3f_vertexbuffer = 0;
7090 rsurface.modelvertex3f_bufferoffset = 0;
7091 rsurface.modelsvector3f_vertexbuffer = 0;
7092 rsurface.modelsvector3f_bufferoffset = 0;
7093 rsurface.modeltvector3f_vertexbuffer = 0;
7094 rsurface.modeltvector3f_bufferoffset = 0;
7095 rsurface.modelnormal3f_vertexbuffer = 0;
7096 rsurface.modelnormal3f_bufferoffset = 0;
7098 rsurface.modelgeneratedvertex = true;
7102 if (rsurface.entityskeletaltransform3x4)
7104 r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7105 r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7106 r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7107 r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7111 r_refdef.stats[r_stat_batch_entitystatic_count]++;
7112 r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7113 r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7114 r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7116 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
7117 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7118 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7119 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7120 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7121 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7122 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7123 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7124 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7125 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
7126 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7127 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7128 rsurface.modelgeneratedvertex = false;
7130 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
7131 rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7132 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7133 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
7134 rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7135 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7136 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
7137 rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7138 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7139 rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7140 rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7141 rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7142 rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7143 rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7144 rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7145 rsurface.modelelement3i = model->surfmesh.data_element3i;
7146 rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7147 rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7148 rsurface.modelelement3s = model->surfmesh.data_element3s;
7149 rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7150 rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7151 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7152 rsurface.modelnumvertices = model->surfmesh.num_vertices;
7153 rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7154 rsurface.modelsurfaces = model->data_surfaces;
7155 rsurface.batchgeneratedvertex = false;
7156 rsurface.batchfirstvertex = 0;
7157 rsurface.batchnumvertices = 0;
7158 rsurface.batchfirsttriangle = 0;
7159 rsurface.batchnumtriangles = 0;
7160 rsurface.batchvertex3f = NULL;
7161 rsurface.batchvertex3f_vertexbuffer = NULL;
7162 rsurface.batchvertex3f_bufferoffset = 0;
7163 rsurface.batchsvector3f = NULL;
7164 rsurface.batchsvector3f_vertexbuffer = NULL;
7165 rsurface.batchsvector3f_bufferoffset = 0;
7166 rsurface.batchtvector3f = NULL;
7167 rsurface.batchtvector3f_vertexbuffer = NULL;
7168 rsurface.batchtvector3f_bufferoffset = 0;
7169 rsurface.batchnormal3f = NULL;
7170 rsurface.batchnormal3f_vertexbuffer = NULL;
7171 rsurface.batchnormal3f_bufferoffset = 0;
7172 rsurface.batchlightmapcolor4f = NULL;
7173 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7174 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7175 rsurface.batchtexcoordtexture2f = NULL;
7176 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7177 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7178 rsurface.batchtexcoordlightmap2f = NULL;
7179 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7180 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7181 rsurface.batchskeletalindex4ub = NULL;
7182 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7183 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7184 rsurface.batchskeletalweight4ub = NULL;
7185 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7186 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7187 rsurface.batchelement3i = NULL;
7188 rsurface.batchelement3i_indexbuffer = NULL;
7189 rsurface.batchelement3i_bufferoffset = 0;
7190 rsurface.batchelement3s = NULL;
7191 rsurface.batchelement3s_indexbuffer = NULL;
7192 rsurface.batchelement3s_bufferoffset = 0;
7193 rsurface.forcecurrenttextureupdate = false;
7196 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, qbool wantnormals, qbool wanttangents)
7198 rsurface.entity = r_refdef.scene.worldentity;
7199 if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7200 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7201 // A better approach could be making this copy only once per frame.
7202 static entity_render_t custom_entity;
7204 custom_entity = *rsurface.entity;
7205 for (q = 0; q < 3; ++q) {
7206 float colormod = q == 0 ? r : q == 1 ? g : b;
7207 custom_entity.render_fullbright[q] *= colormod;
7208 custom_entity.render_modellight_ambient[q] *= colormod;
7209 custom_entity.render_modellight_diffuse[q] *= colormod;
7210 custom_entity.render_lightmap_ambient[q] *= colormod;
7211 custom_entity.render_lightmap_diffuse[q] *= colormod;
7212 custom_entity.render_rtlight_diffuse[q] *= colormod;
7214 custom_entity.alpha *= a;
7215 rsurface.entity = &custom_entity;
7217 rsurface.skeleton = NULL;
7218 rsurface.ent_skinnum = 0;
7219 rsurface.ent_qwskin = -1;
7220 rsurface.ent_flags = entflags;
7221 rsurface.shadertime = r_refdef.scene.time - shadertime;
7222 rsurface.modelnumvertices = numvertices;
7223 rsurface.modelnumtriangles = numtriangles;
7224 rsurface.matrix = *matrix;
7225 rsurface.inversematrix = *inversematrix;
7226 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7227 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7228 R_EntityMatrix(&rsurface.matrix);
7229 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7230 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7231 rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7232 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7233 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7234 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7235 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7236 rsurface.frameblend[0].lerp = 1;
7237 rsurface.ent_alttextures = false;
7238 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7239 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7240 rsurface.entityskeletaltransform3x4 = NULL;
7241 rsurface.entityskeletaltransform3x4buffer = NULL;
7242 rsurface.entityskeletaltransform3x4offset = 0;
7243 rsurface.entityskeletaltransform3x4size = 0;
7244 rsurface.entityskeletalnumtransforms = 0;
7245 r_refdef.stats[r_stat_batch_entitycustom_count]++;
7246 r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7247 r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7248 r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7251 rsurface.modelvertex3f = (float *)vertex3f;
7252 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7253 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7254 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7256 else if (wantnormals)
7258 rsurface.modelvertex3f = (float *)vertex3f;
7259 rsurface.modelsvector3f = NULL;
7260 rsurface.modeltvector3f = NULL;
7261 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7265 rsurface.modelvertex3f = (float *)vertex3f;
7266 rsurface.modelsvector3f = NULL;
7267 rsurface.modeltvector3f = NULL;
7268 rsurface.modelnormal3f = NULL;
7270 rsurface.modelvertex3f_vertexbuffer = 0;
7271 rsurface.modelvertex3f_bufferoffset = 0;
7272 rsurface.modelsvector3f_vertexbuffer = 0;
7273 rsurface.modelsvector3f_bufferoffset = 0;
7274 rsurface.modeltvector3f_vertexbuffer = 0;
7275 rsurface.modeltvector3f_bufferoffset = 0;
7276 rsurface.modelnormal3f_vertexbuffer = 0;
7277 rsurface.modelnormal3f_bufferoffset = 0;
7278 rsurface.modelgeneratedvertex = true;
7279 rsurface.modellightmapcolor4f = (float *)color4f;
7280 rsurface.modellightmapcolor4f_vertexbuffer = 0;
7281 rsurface.modellightmapcolor4f_bufferoffset = 0;
7282 rsurface.modeltexcoordtexture2f = (float *)texcoord2f;
7283 rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7284 rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7285 rsurface.modeltexcoordlightmap2f = NULL;
7286 rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7287 rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7288 rsurface.modelskeletalindex4ub = NULL;
7289 rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7290 rsurface.modelskeletalindex4ub_bufferoffset = 0;
7291 rsurface.modelskeletalweight4ub = NULL;
7292 rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7293 rsurface.modelskeletalweight4ub_bufferoffset = 0;
7294 rsurface.modelelement3i = (int *)element3i;
7295 rsurface.modelelement3i_indexbuffer = NULL;
7296 rsurface.modelelement3i_bufferoffset = 0;
7297 rsurface.modelelement3s = (unsigned short *)element3s;
7298 rsurface.modelelement3s_indexbuffer = NULL;
7299 rsurface.modelelement3s_bufferoffset = 0;
7300 rsurface.modellightmapoffsets = NULL;
7301 rsurface.modelsurfaces = NULL;
7302 rsurface.batchgeneratedvertex = false;
7303 rsurface.batchfirstvertex = 0;
7304 rsurface.batchnumvertices = 0;
7305 rsurface.batchfirsttriangle = 0;
7306 rsurface.batchnumtriangles = 0;
7307 rsurface.batchvertex3f = NULL;
7308 rsurface.batchvertex3f_vertexbuffer = NULL;
7309 rsurface.batchvertex3f_bufferoffset = 0;
7310 rsurface.batchsvector3f = NULL;
7311 rsurface.batchsvector3f_vertexbuffer = NULL;
7312 rsurface.batchsvector3f_bufferoffset = 0;
7313 rsurface.batchtvector3f = NULL;
7314 rsurface.batchtvector3f_vertexbuffer = NULL;
7315 rsurface.batchtvector3f_bufferoffset = 0;
7316 rsurface.batchnormal3f = NULL;
7317 rsurface.batchnormal3f_vertexbuffer = NULL;
7318 rsurface.batchnormal3f_bufferoffset = 0;
7319 rsurface.batchlightmapcolor4f = NULL;
7320 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7321 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7322 rsurface.batchtexcoordtexture2f = NULL;
7323 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7324 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7325 rsurface.batchtexcoordlightmap2f = NULL;
7326 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7327 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7328 rsurface.batchskeletalindex4ub = NULL;
7329 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7330 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7331 rsurface.batchskeletalweight4ub = NULL;
7332 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7333 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7334 rsurface.batchelement3i = NULL;
7335 rsurface.batchelement3i_indexbuffer = NULL;
7336 rsurface.batchelement3i_bufferoffset = 0;
7337 rsurface.batchelement3s = NULL;
7338 rsurface.batchelement3s_indexbuffer = NULL;
7339 rsurface.batchelement3s_bufferoffset = 0;
7340 rsurface.forcecurrenttextureupdate = true;
7342 if (rsurface.modelnumvertices && rsurface.modelelement3i)
7344 if ((wantnormals || wanttangents) && !normal3f)
7346 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7347 Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7349 if (wanttangents && !svector3f)
7351 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7352 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7353 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7358 float RSurf_FogPoint(const float *v)
7360 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7361 float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7362 float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7363 float FogHeightFade = r_refdef.fogheightfade;
7365 unsigned int fogmasktableindex;
7366 if (r_refdef.fogplaneviewabove)
7367 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7369 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7370 fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7371 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7374 float RSurf_FogVertex(const float *v)
7376 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7377 float FogPlaneViewDist = rsurface.fogplaneviewdist;
7378 float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7379 float FogHeightFade = rsurface.fogheightfade;
7381 unsigned int fogmasktableindex;
7382 if (r_refdef.fogplaneviewabove)
7383 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7385 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7386 fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7387 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7390 void RSurf_UploadBuffersForBatch(void)
7392 // upload buffer data for generated vertex data (dynamicvertex case) or index data (copytriangles case) and models that lack it to begin with (e.g. DrawQ_FlushUI)
7393 // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7394 if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7395 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7396 if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7397 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7398 if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7399 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7400 if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7401 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7402 if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7403 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7404 if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7405 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7406 if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7407 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7408 if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7409 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7410 if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7411 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7413 if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7414 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7415 else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7416 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7418 R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7419 R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7420 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7421 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7422 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7423 R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7424 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7425 R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7426 R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7427 R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7430 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7433 for (i = 0;i < numelements;i++)
7434 outelement3i[i] = inelement3i[i] + adjust;
7437 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7438 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7446 int surfacefirsttriangle;
7447 int surfacenumtriangles;
7448 int surfacefirstvertex;
7449 int surfaceendvertex;
7450 int surfacenumvertices;
7451 int batchnumsurfaces = texturenumsurfaces;
7452 int batchnumvertices;
7453 int batchnumtriangles;
7456 qbool dynamicvertex;
7459 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7462 q3shaderinfo_deform_t *deform;
7463 const msurface_t *surface, *firstsurface;
7464 if (!texturenumsurfaces)
7466 // find vertex range of this surface batch
7468 firstsurface = texturesurfacelist[0];
7469 firsttriangle = firstsurface->num_firsttriangle;
7470 batchnumvertices = 0;
7471 batchnumtriangles = 0;
7472 firstvertex = endvertex = firstsurface->num_firstvertex;
7473 for (i = 0;i < texturenumsurfaces;i++)
7475 surface = texturesurfacelist[i];
7476 if (surface != firstsurface + i)
7478 surfacefirstvertex = surface->num_firstvertex;
7479 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7480 surfacenumvertices = surface->num_vertices;
7481 surfacenumtriangles = surface->num_triangles;
7482 if (firstvertex > surfacefirstvertex)
7483 firstvertex = surfacefirstvertex;
7484 if (endvertex < surfaceendvertex)
7485 endvertex = surfaceendvertex;
7486 batchnumvertices += surfacenumvertices;
7487 batchnumtriangles += surfacenumtriangles;
7490 r_refdef.stats[r_stat_batch_batches]++;
7492 r_refdef.stats[r_stat_batch_withgaps]++;
7493 r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7494 r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7495 r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7497 // we now know the vertex range used, and if there are any gaps in it
7498 rsurface.batchfirstvertex = firstvertex;
7499 rsurface.batchnumvertices = endvertex - firstvertex;
7500 rsurface.batchfirsttriangle = firsttriangle;
7501 rsurface.batchnumtriangles = batchnumtriangles;
7503 // check if any dynamic vertex processing must occur
7504 dynamicvertex = false;
7506 // we must use vertexbuffers for rendering, we can upload vertex buffers
7507 // easily enough but if the basevertex is non-zero it becomes more
7508 // difficult, so force dynamicvertex path in that case - it's suboptimal
7509 // but the most optimal case is to have the geometry sources provide their
7511 if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7512 dynamicvertex = true;
7514 // a cvar to force the dynamic vertex path to be taken, for debugging
7515 if (r_batch_debugdynamicvertexpath.integer)
7519 r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7520 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7521 r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7522 r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7524 dynamicvertex = true;
7527 // if there is a chance of animated vertex colors, it's a dynamic batch
7528 if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7532 r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7533 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7534 r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7535 r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7537 dynamicvertex = true;
7540 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7542 switch (deform->deform)
7545 case Q3DEFORM_PROJECTIONSHADOW:
7546 case Q3DEFORM_TEXT0:
7547 case Q3DEFORM_TEXT1:
7548 case Q3DEFORM_TEXT2:
7549 case Q3DEFORM_TEXT3:
7550 case Q3DEFORM_TEXT4:
7551 case Q3DEFORM_TEXT5:
7552 case Q3DEFORM_TEXT6:
7553 case Q3DEFORM_TEXT7:
7556 case Q3DEFORM_AUTOSPRITE:
7559 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7560 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7561 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7562 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7564 dynamicvertex = true;
7565 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7567 case Q3DEFORM_AUTOSPRITE2:
7570 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7571 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7572 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7573 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7575 dynamicvertex = true;
7576 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7578 case Q3DEFORM_NORMAL:
7581 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7582 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7583 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7584 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7586 dynamicvertex = true;
7587 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7590 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7591 break; // if wavefunc is a nop, ignore this transform
7594 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7595 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7596 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7597 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7599 dynamicvertex = true;
7600 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7602 case Q3DEFORM_BULGE:
7605 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7606 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7607 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7608 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7610 dynamicvertex = true;
7611 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7614 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7615 break; // if wavefunc is a nop, ignore this transform
7618 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7619 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7620 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7621 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7623 dynamicvertex = true;
7624 batchneed |= BATCHNEED_ARRAY_VERTEX;
7628 if (rsurface.texture->materialshaderpass)
7630 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7633 case Q3TCGEN_TEXTURE:
7635 case Q3TCGEN_LIGHTMAP:
7638 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7639 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7640 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7641 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7643 dynamicvertex = true;
7644 batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7646 case Q3TCGEN_VECTOR:
7649 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7650 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7651 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7652 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7654 dynamicvertex = true;
7655 batchneed |= BATCHNEED_ARRAY_VERTEX;
7657 case Q3TCGEN_ENVIRONMENT:
7660 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7661 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7662 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7663 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7665 dynamicvertex = true;
7666 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7669 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7673 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7674 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7675 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7676 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7678 dynamicvertex = true;
7679 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7683 // the caller can specify BATCHNEED_NOGAPS to force a batch with
7684 // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7685 // we ensure this by treating the vertex batch as dynamic...
7686 if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7690 r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7691 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7692 r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7693 r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7695 dynamicvertex = true;
7698 // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7699 if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7700 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7702 rsurface.batchvertex3f = rsurface.modelvertex3f;
7703 rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7704 rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7705 rsurface.batchsvector3f = rsurface.modelsvector3f;
7706 rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7707 rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7708 rsurface.batchtvector3f = rsurface.modeltvector3f;
7709 rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7710 rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7711 rsurface.batchnormal3f = rsurface.modelnormal3f;
7712 rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7713 rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7714 rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7715 rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer;
7716 rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
7717 rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7718 rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer;
7719 rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
7720 rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7721 rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7722 rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7723 rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7724 rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7725 rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7726 rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7727 rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7728 rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7729 rsurface.batchelement3i = rsurface.modelelement3i;
7730 rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7731 rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7732 rsurface.batchelement3s = rsurface.modelelement3s;
7733 rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7734 rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7735 rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7736 rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7737 rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7738 rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7739 rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7741 // if any dynamic vertex processing has to occur in software, we copy the
7742 // entire surface list together before processing to rebase the vertices
7743 // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7745 // if any gaps exist and we do not have a static vertex buffer, we have to
7746 // copy the surface list together to avoid wasting upload bandwidth on the
7747 // vertices in the gaps.
7749 // if gaps exist and we have a static vertex buffer, we can choose whether
7750 // to combine the index buffer ranges into one dynamic index buffer or
7751 // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7753 // in many cases the batch is reduced to one draw call.
7755 rsurface.batchmultidraw = false;
7756 rsurface.batchmultidrawnumsurfaces = 0;
7757 rsurface.batchmultidrawsurfacelist = NULL;
7761 // static vertex data, just set pointers...
7762 rsurface.batchgeneratedvertex = false;
7763 // if there are gaps, we want to build a combined index buffer,
7764 // otherwise use the original static buffer with an appropriate offset
7767 r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7768 r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7769 r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7770 r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7771 if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7773 rsurface.batchmultidraw = true;
7774 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7775 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7778 // build a new triangle elements array for this batch
7779 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7780 rsurface.batchfirsttriangle = 0;
7782 for (i = 0;i < texturenumsurfaces;i++)
7784 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7785 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7786 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7787 numtriangles += surfacenumtriangles;
7789 rsurface.batchelement3i_indexbuffer = NULL;
7790 rsurface.batchelement3i_bufferoffset = 0;
7791 rsurface.batchelement3s = NULL;
7792 rsurface.batchelement3s_indexbuffer = NULL;
7793 rsurface.batchelement3s_bufferoffset = 0;
7794 if (endvertex <= 65536)
7796 // make a 16bit (unsigned short) index array if possible
7797 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7798 for (i = 0;i < numtriangles*3;i++)
7799 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7804 r_refdef.stats[r_stat_batch_fast_batches] += 1;
7805 r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7806 r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7807 r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7812 // something needs software processing, do it for real...
7813 // we only directly handle separate array data in this case and then
7814 // generate interleaved data if needed...
7815 rsurface.batchgeneratedvertex = true;
7816 r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7817 r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7818 r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7819 r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7821 // now copy the vertex data into a combined array and make an index array
7822 // (this is what Quake3 does all the time)
7823 // we also apply any skeletal animation here that would have been done in
7824 // the vertex shader, because most of the dynamic vertex animation cases
7825 // need actual vertex positions and normals
7826 //if (dynamicvertex)
7828 rsurface.batchvertex3f = NULL;
7829 rsurface.batchvertex3f_vertexbuffer = NULL;
7830 rsurface.batchvertex3f_bufferoffset = 0;
7831 rsurface.batchsvector3f = NULL;
7832 rsurface.batchsvector3f_vertexbuffer = NULL;
7833 rsurface.batchsvector3f_bufferoffset = 0;
7834 rsurface.batchtvector3f = NULL;
7835 rsurface.batchtvector3f_vertexbuffer = NULL;
7836 rsurface.batchtvector3f_bufferoffset = 0;
7837 rsurface.batchnormal3f = NULL;
7838 rsurface.batchnormal3f_vertexbuffer = NULL;
7839 rsurface.batchnormal3f_bufferoffset = 0;
7840 rsurface.batchlightmapcolor4f = NULL;
7841 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7842 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7843 rsurface.batchtexcoordtexture2f = NULL;
7844 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7845 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7846 rsurface.batchtexcoordlightmap2f = NULL;
7847 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7848 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7849 rsurface.batchskeletalindex4ub = NULL;
7850 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7851 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7852 rsurface.batchskeletalweight4ub = NULL;
7853 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7854 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7855 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7856 rsurface.batchelement3i_indexbuffer = NULL;
7857 rsurface.batchelement3i_bufferoffset = 0;
7858 rsurface.batchelement3s = NULL;
7859 rsurface.batchelement3s_indexbuffer = NULL;
7860 rsurface.batchelement3s_bufferoffset = 0;
7861 rsurface.batchskeletaltransform3x4buffer = NULL;
7862 rsurface.batchskeletaltransform3x4offset = 0;
7863 rsurface.batchskeletaltransform3x4size = 0;
7864 // we'll only be setting up certain arrays as needed
7865 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7866 rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7867 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7868 rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7869 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7871 rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7872 rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7874 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7875 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7876 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7877 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7878 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7879 rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7880 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7882 rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7883 rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7887 for (i = 0;i < texturenumsurfaces;i++)
7889 surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7890 surfacenumvertices = texturesurfacelist[i]->num_vertices;
7891 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7892 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7893 // copy only the data requested
7894 if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7896 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7898 if (rsurface.batchvertex3f)
7899 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7901 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7903 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7905 if (rsurface.modelnormal3f)
7906 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7908 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7910 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7912 if (rsurface.modelsvector3f)
7914 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7915 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7919 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7920 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7923 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7925 if (rsurface.modellightmapcolor4f)
7926 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7928 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7930 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7932 if (rsurface.modeltexcoordtexture2f)
7933 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7935 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7937 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7939 if (rsurface.modeltexcoordlightmap2f)
7940 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7942 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7944 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7946 if (rsurface.modelskeletalindex4ub)
7948 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7949 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7953 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7954 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7955 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7956 for (j = 0;j < surfacenumvertices;j++)
7961 RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7962 numvertices += surfacenumvertices;
7963 numtriangles += surfacenumtriangles;
7966 // generate a 16bit index array as well if possible
7967 // (in general, dynamic batches fit)
7968 if (numvertices <= 65536)
7970 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7971 for (i = 0;i < numtriangles*3;i++)
7972 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7975 // since we've copied everything, the batch now starts at 0
7976 rsurface.batchfirstvertex = 0;
7977 rsurface.batchnumvertices = batchnumvertices;
7978 rsurface.batchfirsttriangle = 0;
7979 rsurface.batchnumtriangles = batchnumtriangles;
7982 // apply skeletal animation that would have been done in the vertex shader
7983 if (rsurface.batchskeletaltransform3x4)
7985 const unsigned char *si;
7986 const unsigned char *sw;
7988 const float *b = rsurface.batchskeletaltransform3x4;
7989 float *vp, *vs, *vt, *vn;
7991 float m[3][4], n[3][4];
7992 float tp[3], ts[3], tt[3], tn[3];
7993 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7994 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7995 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7996 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7997 si = rsurface.batchskeletalindex4ub;
7998 sw = rsurface.batchskeletalweight4ub;
7999 vp = rsurface.batchvertex3f;
8000 vs = rsurface.batchsvector3f;
8001 vt = rsurface.batchtvector3f;
8002 vn = rsurface.batchnormal3f;
8003 memset(m[0], 0, sizeof(m));
8004 memset(n[0], 0, sizeof(n));
8005 for (i = 0;i < batchnumvertices;i++)
8007 t[0] = b + si[0]*12;
8010 // common case - only one matrix
8024 else if (sw[2] + sw[3])
8027 t[1] = b + si[1]*12;
8028 t[2] = b + si[2]*12;
8029 t[3] = b + si[3]*12;
8030 w[0] = sw[0] * (1.0f / 255.0f);
8031 w[1] = sw[1] * (1.0f / 255.0f);
8032 w[2] = sw[2] * (1.0f / 255.0f);
8033 w[3] = sw[3] * (1.0f / 255.0f);
8034 // blend the matrices
8035 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8036 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8037 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8038 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8039 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8040 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8041 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8042 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8043 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8044 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8045 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8046 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8051 t[1] = b + si[1]*12;
8052 w[0] = sw[0] * (1.0f / 255.0f);
8053 w[1] = sw[1] * (1.0f / 255.0f);
8054 // blend the matrices
8055 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8056 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8057 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8058 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8059 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8060 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8061 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8062 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8063 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8064 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8065 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8066 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8070 // modify the vertex
8072 vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8073 vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8074 vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8078 // the normal transformation matrix is a set of cross products...
8079 CrossProduct(m[1], m[2], n[0]);
8080 CrossProduct(m[2], m[0], n[1]);
8081 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8083 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8084 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8085 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8086 VectorNormalize(vn);
8091 vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8092 vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8093 vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8094 VectorNormalize(vs);
8097 vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8098 vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8099 vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8100 VectorNormalize(vt);
8105 rsurface.batchskeletaltransform3x4 = NULL;
8106 rsurface.batchskeletalnumtransforms = 0;
8109 // q1bsp surfaces rendered in vertex color mode have to have colors
8110 // calculated based on lightstyles
8111 if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8113 // generate color arrays for the surfaces in this list
8118 const unsigned char *lm;
8119 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8120 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8121 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8123 for (i = 0;i < texturenumsurfaces;i++)
8125 surface = texturesurfacelist[i];
8126 offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8127 surfacenumvertices = surface->num_vertices;
8128 if (surface->lightmapinfo->samples)
8130 for (j = 0;j < surfacenumvertices;j++)
8132 lm = surface->lightmapinfo->samples + offsets[j];
8133 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8134 VectorScale(lm, scale, c);
8135 if (surface->lightmapinfo->styles[1] != 255)
8137 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8139 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8140 VectorMA(c, scale, lm, c);
8141 if (surface->lightmapinfo->styles[2] != 255)
8144 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8145 VectorMA(c, scale, lm, c);
8146 if (surface->lightmapinfo->styles[3] != 255)
8149 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8150 VectorMA(c, scale, lm, c);
8157 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);
8163 for (j = 0;j < surfacenumvertices;j++)
8165 Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8172 // if vertices are deformed (sprite flares and things in maps, possibly
8173 // water waves, bulges and other deformations), modify the copied vertices
8175 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8178 switch (deform->deform)
8181 case Q3DEFORM_PROJECTIONSHADOW:
8182 case Q3DEFORM_TEXT0:
8183 case Q3DEFORM_TEXT1:
8184 case Q3DEFORM_TEXT2:
8185 case Q3DEFORM_TEXT3:
8186 case Q3DEFORM_TEXT4:
8187 case Q3DEFORM_TEXT5:
8188 case Q3DEFORM_TEXT6:
8189 case Q3DEFORM_TEXT7:
8192 case Q3DEFORM_AUTOSPRITE:
8193 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8194 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8195 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8196 VectorNormalize(newforward);
8197 VectorNormalize(newright);
8198 VectorNormalize(newup);
8199 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8200 // rsurface.batchvertex3f_vertexbuffer = NULL;
8201 // rsurface.batchvertex3f_bufferoffset = 0;
8202 // rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8203 // rsurface.batchsvector3f_vertexbuffer = NULL;
8204 // rsurface.batchsvector3f_bufferoffset = 0;
8205 // rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8206 // rsurface.batchtvector3f_vertexbuffer = NULL;
8207 // rsurface.batchtvector3f_bufferoffset = 0;
8208 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8209 // rsurface.batchnormal3f_vertexbuffer = NULL;
8210 // rsurface.batchnormal3f_bufferoffset = 0;
8211 // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8212 if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8213 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8214 if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8215 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);
8216 // a single autosprite surface can contain multiple sprites...
8217 for (j = 0;j < batchnumvertices - 3;j += 4)
8219 VectorClear(center);
8220 for (i = 0;i < 4;i++)
8221 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8222 VectorScale(center, 0.25f, center);
8223 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8224 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8225 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8226 for (i = 0;i < 4;i++)
8228 VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8229 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8232 // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8233 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8234 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);
8236 case Q3DEFORM_AUTOSPRITE2:
8237 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8238 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8239 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8240 VectorNormalize(newforward);
8241 VectorNormalize(newright);
8242 VectorNormalize(newup);
8243 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8244 // rsurface.batchvertex3f_vertexbuffer = NULL;
8245 // rsurface.batchvertex3f_bufferoffset = 0;
8247 const float *v1, *v2;
8257 memset(shortest, 0, sizeof(shortest));
8258 // a single autosprite surface can contain multiple sprites...
8259 for (j = 0;j < batchnumvertices - 3;j += 4)
8261 VectorClear(center);
8262 for (i = 0;i < 4;i++)
8263 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8264 VectorScale(center, 0.25f, center);
8265 // find the two shortest edges, then use them to define the
8266 // axis vectors for rotating around the central axis
8267 for (i = 0;i < 6;i++)
8269 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8270 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8271 l = VectorDistance2(v1, v2);
8272 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8274 l += (1.0f / 1024.0f);
8275 if (shortest[0].length2 > l || i == 0)
8277 shortest[1] = shortest[0];
8278 shortest[0].length2 = l;
8279 shortest[0].v1 = v1;
8280 shortest[0].v2 = v2;
8282 else if (shortest[1].length2 > l || i == 1)
8284 shortest[1].length2 = l;
8285 shortest[1].v1 = v1;
8286 shortest[1].v2 = v2;
8289 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8290 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8291 // this calculates the right vector from the shortest edge
8292 // and the up vector from the edge midpoints
8293 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8294 VectorNormalize(right);
8295 VectorSubtract(end, start, up);
8296 VectorNormalize(up);
8297 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8298 VectorSubtract(rsurface.localvieworigin, center, forward);
8299 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8300 VectorNegate(forward, forward);
8301 VectorReflect(forward, 0, up, forward);
8302 VectorNormalize(forward);
8303 CrossProduct(up, forward, newright);
8304 VectorNormalize(newright);
8305 // rotate the quad around the up axis vector, this is made
8306 // especially easy by the fact we know the quad is flat,
8307 // so we only have to subtract the center position and
8308 // measure distance along the right vector, and then
8309 // multiply that by the newright vector and add back the
8311 // we also need to subtract the old position to undo the
8312 // displacement from the center, which we do with a
8313 // DotProduct, the subtraction/addition of center is also
8314 // optimized into DotProducts here
8315 l = DotProduct(right, center);
8316 for (i = 0;i < 4;i++)
8318 v1 = rsurface.batchvertex3f + 3*(j+i);
8319 f = DotProduct(right, v1) - l;
8320 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8324 if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8326 // rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8327 // rsurface.batchnormal3f_vertexbuffer = NULL;
8328 // rsurface.batchnormal3f_bufferoffset = 0;
8329 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8331 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8333 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8334 // rsurface.batchsvector3f_vertexbuffer = NULL;
8335 // rsurface.batchsvector3f_bufferoffset = 0;
8336 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8337 // rsurface.batchtvector3f_vertexbuffer = NULL;
8338 // rsurface.batchtvector3f_bufferoffset = 0;
8339 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);
8342 case Q3DEFORM_NORMAL:
8343 // deform the normals to make reflections wavey
8344 rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8345 rsurface.batchnormal3f_vertexbuffer = NULL;
8346 rsurface.batchnormal3f_bufferoffset = 0;
8347 for (j = 0;j < batchnumvertices;j++)
8350 float *normal = rsurface.batchnormal3f + 3*j;
8351 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8352 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8353 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8354 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8355 VectorNormalize(normal);
8357 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8359 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8360 // rsurface.batchsvector3f_vertexbuffer = NULL;
8361 // rsurface.batchsvector3f_bufferoffset = 0;
8362 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8363 // rsurface.batchtvector3f_vertexbuffer = NULL;
8364 // rsurface.batchtvector3f_bufferoffset = 0;
8365 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);
8369 // deform vertex array to make wavey water and flags and such
8370 waveparms[0] = deform->waveparms[0];
8371 waveparms[1] = deform->waveparms[1];
8372 waveparms[2] = deform->waveparms[2];
8373 waveparms[3] = deform->waveparms[3];
8374 if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8375 break; // if wavefunc is a nop, don't make a dynamic vertex array
8376 // this is how a divisor of vertex influence on deformation
8377 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8378 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8379 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8380 // rsurface.batchvertex3f_vertexbuffer = NULL;
8381 // rsurface.batchvertex3f_bufferoffset = 0;
8382 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8383 // rsurface.batchnormal3f_vertexbuffer = NULL;
8384 // rsurface.batchnormal3f_bufferoffset = 0;
8385 for (j = 0;j < batchnumvertices;j++)
8387 // if the wavefunc depends on time, evaluate it per-vertex
8390 waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8391 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8393 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8395 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8396 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8397 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8399 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8400 // rsurface.batchsvector3f_vertexbuffer = NULL;
8401 // rsurface.batchsvector3f_bufferoffset = 0;
8402 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8403 // rsurface.batchtvector3f_vertexbuffer = NULL;
8404 // rsurface.batchtvector3f_bufferoffset = 0;
8405 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);
8408 case Q3DEFORM_BULGE:
8409 // deform vertex array to make the surface have moving bulges
8410 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8411 // rsurface.batchvertex3f_vertexbuffer = NULL;
8412 // rsurface.batchvertex3f_bufferoffset = 0;
8413 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8414 // rsurface.batchnormal3f_vertexbuffer = NULL;
8415 // rsurface.batchnormal3f_bufferoffset = 0;
8416 for (j = 0;j < batchnumvertices;j++)
8418 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8419 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8421 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8422 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8423 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8425 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8426 // rsurface.batchsvector3f_vertexbuffer = NULL;
8427 // rsurface.batchsvector3f_bufferoffset = 0;
8428 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8429 // rsurface.batchtvector3f_vertexbuffer = NULL;
8430 // rsurface.batchtvector3f_bufferoffset = 0;
8431 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);
8435 // deform vertex array
8436 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8437 break; // if wavefunc is a nop, don't make a dynamic vertex array
8438 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8439 VectorScale(deform->parms, scale, waveparms);
8440 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8441 // rsurface.batchvertex3f_vertexbuffer = NULL;
8442 // rsurface.batchvertex3f_bufferoffset = 0;
8443 for (j = 0;j < batchnumvertices;j++)
8444 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8449 if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8451 // generate texcoords based on the chosen texcoord source
8452 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8455 case Q3TCGEN_TEXTURE:
8457 case Q3TCGEN_LIGHTMAP:
8458 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8459 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8460 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8461 if (rsurface.batchtexcoordlightmap2f)
8462 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8464 case Q3TCGEN_VECTOR:
8465 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8466 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8467 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8468 for (j = 0;j < batchnumvertices;j++)
8470 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8471 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8474 case Q3TCGEN_ENVIRONMENT:
8475 // make environment reflections using a spheremap
8476 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8477 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8478 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8479 for (j = 0;j < batchnumvertices;j++)
8481 // identical to Q3A's method, but executed in worldspace so
8482 // carried models can be shiny too
8484 float viewer[3], d, reflected[3], worldreflected[3];
8486 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8487 // VectorNormalize(viewer);
8489 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8491 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8492 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8493 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8494 // note: this is proportinal to viewer, so we can normalize later
8496 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8497 VectorNormalize(worldreflected);
8499 // note: this sphere map only uses world x and z!
8500 // so positive and negative y will LOOK THE SAME.
8501 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8502 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8506 // the only tcmod that needs software vertex processing is turbulent, so
8507 // check for it here and apply the changes if needed
8508 // and we only support that as the first one
8509 // (handling a mixture of turbulent and other tcmods would be problematic
8510 // without punting it entirely to a software path)
8511 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8513 amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8514 animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8515 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8516 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8517 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8518 for (j = 0;j < batchnumvertices;j++)
8520 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);
8521 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8527 void RSurf_DrawBatch(void)
8529 // sometimes a zero triangle surface (usually a degenerate patch) makes it
8530 // through the pipeline, killing it earlier in the pipeline would have
8531 // per-surface overhead rather than per-batch overhead, so it's best to
8532 // reject it here, before it hits glDraw.
8533 if (rsurface.batchnumtriangles == 0)
8536 // batch debugging code
8537 if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8543 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8544 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8547 for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8549 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8551 if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8552 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);
8559 if (rsurface.batchmultidraw)
8561 // issue multiple draws rather than copying index data
8562 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8563 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8564 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8565 for (i = 0;i < numsurfaces;)
8567 // combine consecutive surfaces as one draw
8568 for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8569 if (surfacelist[j] != surfacelist[k] + 1)
8571 firstvertex = surfacelist[i]->num_firstvertex;
8572 endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8573 firsttriangle = surfacelist[i]->num_firsttriangle;
8574 endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8575 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);
8581 // there is only one consecutive run of index data (may have been combined)
8582 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);
8586 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8588 // pick the closest matching water plane
8589 int planeindex, vertexindex, bestplaneindex = -1;
8593 r_waterstate_waterplane_t *p;
8594 qbool prepared = false;
8596 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8598 if(p->camera_entity != rsurface.texture->camera_entity)
8603 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8605 if(rsurface.batchnumvertices == 0)
8608 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8610 Matrix4x4_Transform(&rsurface.matrix, v, vert);
8611 d += fabs(PlaneDiff(vert, &p->plane));
8613 if (bestd > d || bestplaneindex < 0)
8616 bestplaneindex = planeindex;
8619 return bestplaneindex;
8620 // NOTE: this MAY return a totally unrelated water plane; we can ignore
8621 // this situation though, as it might be better to render single larger
8622 // batches with useless stuff (backface culled for example) than to
8623 // render multiple smaller batches
8626 void RSurf_SetupDepthAndCulling(void)
8628 // submodels are biased to avoid z-fighting with world surfaces that they
8629 // may be exactly overlapping (avoids z-fighting artifacts on certain
8630 // doors and things in Quake maps)
8631 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8632 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8633 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8634 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8637 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8641 float p[3], mins[3], maxs[3];
8643 // transparent sky would be ridiculous
8644 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8646 R_SetupShader_Generic_NoTexture(false, false);
8647 skyrenderlater = true;
8648 RSurf_SetupDepthAndCulling();
8651 // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8652 if (r_sky_scissor.integer)
8654 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8655 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8657 Matrix4x4_Transform(&rsurface.matrix, v, p);
8660 if (mins[0] > p[0]) mins[0] = p[0];
8661 if (mins[1] > p[1]) mins[1] = p[1];
8662 if (mins[2] > p[2]) mins[2] = p[2];
8663 if (maxs[0] < p[0]) maxs[0] = p[0];
8664 if (maxs[1] < p[1]) maxs[1] = p[1];
8665 if (maxs[2] < p[2]) maxs[2] = p[2];
8669 VectorCopy(p, mins);
8670 VectorCopy(p, maxs);
8673 if (!R_ScissorForBBox(mins, maxs, scissor))
8677 if (skyscissor[0] > scissor[0])
8679 skyscissor[2] += skyscissor[0] - scissor[0];
8680 skyscissor[0] = scissor[0];
8682 if (skyscissor[1] > scissor[1])
8684 skyscissor[3] += skyscissor[1] - scissor[1];
8685 skyscissor[1] = scissor[1];
8687 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8688 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8689 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8690 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8693 Vector4Copy(scissor, skyscissor);
8697 // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8698 // skymasking on them, and Quake3 never did sky masking (unlike
8699 // software Quake and software Quake2), so disable the sky masking
8700 // in Quake3 maps as it causes problems with q3map2 sky tricks,
8701 // and skymasking also looks very bad when noclipping outside the
8702 // level, so don't use it then either.
8703 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)
8705 R_Mesh_ResetTextureState();
8706 if (skyrendermasked)
8708 R_SetupShader_DepthOrShadow(false, false, false);
8709 // depth-only (masking)
8710 GL_ColorMask(0, 0, 0, 0);
8711 // just to make sure that braindead drivers don't draw
8712 // anything despite that colormask...
8713 GL_BlendFunc(GL_ZERO, GL_ONE);
8714 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8715 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8719 R_SetupShader_Generic_NoTexture(false, false);
8721 GL_BlendFunc(GL_ONE, GL_ZERO);
8722 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8723 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8724 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8727 if (skyrendermasked)
8728 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8730 R_Mesh_ResetTextureState();
8731 GL_Color(1, 1, 1, 1);
8734 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8735 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8736 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8738 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8742 // render screenspace normalmap to texture
8744 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8749 // bind lightmap texture
8751 // water/refraction/reflection/camera surfaces have to be handled specially
8752 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8754 int start, end, startplaneindex;
8755 for (start = 0;start < texturenumsurfaces;start = end)
8757 startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8758 if(startplaneindex < 0)
8760 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8761 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8765 for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8767 // now that we have a batch using the same planeindex, render it
8768 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8770 // render water or distortion background
8772 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8774 // blend surface on top
8775 GL_DepthMask(false);
8776 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8779 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8781 // render surface with reflection texture as input
8782 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8783 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8790 // render surface batch normally
8791 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8792 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8796 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8800 int texturesurfaceindex;
8802 const msurface_t *surface;
8803 float surfacecolor4f[4];
8805 // R_Mesh_ResetTextureState();
8806 R_SetupShader_Generic_NoTexture(false, false);
8808 GL_BlendFunc(GL_ONE, GL_ZERO);
8809 GL_DepthMask(writedepth);
8811 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8813 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8815 surface = texturesurfacelist[texturesurfaceindex];
8816 k = (int)(((size_t)surface) / sizeof(msurface_t));
8817 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8818 for (j = 0;j < surface->num_vertices;j++)
8820 Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8824 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8828 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8831 RSurf_SetupDepthAndCulling();
8832 if (r_showsurfaces.integer && r_refdef.view.showdebug)
8834 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8837 switch (vid.renderpath)
8839 case RENDERPATH_GL32:
8840 case RENDERPATH_GLES2:
8841 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8847 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8850 int texturenumsurfaces, endsurface;
8852 const msurface_t *surface;
8853 const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8855 RSurf_ActiveModelEntity(ent, true, true, false);
8857 if (r_transparentdepthmasking.integer)
8859 qbool setup = false;
8860 for (i = 0;i < numsurfaces;i = j)
8863 surface = rsurface.modelsurfaces + surfacelist[i];
8864 texture = surface->texture;
8865 rsurface.texture = R_GetCurrentTexture(texture);
8866 rsurface.lightmaptexture = NULL;
8867 rsurface.deluxemaptexture = NULL;
8868 rsurface.uselightmaptexture = false;
8869 // scan ahead until we find a different texture
8870 endsurface = min(i + 1024, numsurfaces);
8871 texturenumsurfaces = 0;
8872 texturesurfacelist[texturenumsurfaces++] = surface;
8873 for (;j < endsurface;j++)
8875 surface = rsurface.modelsurfaces + surfacelist[j];
8876 if (texture != surface->texture)
8878 texturesurfacelist[texturenumsurfaces++] = surface;
8880 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8882 // render the range of surfaces as depth
8886 GL_ColorMask(0,0,0,0);
8889 GL_BlendFunc(GL_ONE, GL_ZERO);
8891 // R_Mesh_ResetTextureState();
8893 RSurf_SetupDepthAndCulling();
8894 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8895 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8896 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8900 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8903 for (i = 0;i < numsurfaces;i = j)
8906 surface = rsurface.modelsurfaces + surfacelist[i];
8907 texture = surface->texture;
8908 rsurface.texture = R_GetCurrentTexture(texture);
8909 // scan ahead until we find a different texture
8910 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8911 texturenumsurfaces = 0;
8912 texturesurfacelist[texturenumsurfaces++] = surface;
8913 rsurface.lightmaptexture = surface->lightmaptexture;
8914 rsurface.deluxemaptexture = surface->deluxemaptexture;
8915 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8916 for (;j < endsurface;j++)
8918 surface = rsurface.modelsurfaces + surfacelist[j];
8919 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8921 texturesurfacelist[texturenumsurfaces++] = surface;
8923 // render the range of surfaces
8924 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8926 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8929 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8931 // transparent surfaces get pushed off into the transparent queue
8932 int surfacelistindex;
8933 const msurface_t *surface;
8934 vec3_t tempcenter, center;
8935 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8937 surface = texturesurfacelist[surfacelistindex];
8938 if (r_transparent_sortsurfacesbynearest.integer)
8940 tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8941 tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8942 tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8946 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8947 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8948 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8950 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8951 if (rsurface.entity->transparent_offset) // transparent offset
8953 center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8954 center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8955 center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8957 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);
8961 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8963 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8965 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8967 RSurf_SetupDepthAndCulling();
8968 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8969 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8970 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8974 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
8978 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8980 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8983 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8985 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8986 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8988 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8990 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8991 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8992 else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8994 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8996 // in the deferred case, transparent surfaces were queued during prepass
8997 if (!r_shadow_usingdeferredprepass)
8998 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9002 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9003 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9008 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9012 R_FrameData_SetMark();
9013 // break the surface list down into batches by texture and use of lightmapping
9014 for (i = 0;i < numsurfaces;i = j)
9017 // texture is the base texture pointer, rsurface.texture is the
9018 // current frame/skin the texture is directing us to use (for example
9019 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9020 // use skin 1 instead)
9021 texture = surfacelist[i]->texture;
9022 rsurface.texture = R_GetCurrentTexture(texture);
9023 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9025 // if this texture is not the kind we want, skip ahead to the next one
9026 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9030 if(depthonly || prepass)
9032 rsurface.lightmaptexture = NULL;
9033 rsurface.deluxemaptexture = NULL;
9034 rsurface.uselightmaptexture = false;
9035 // simply scan ahead until we find a different texture or lightmap state
9036 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9041 rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9042 rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9043 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9044 // simply scan ahead until we find a different texture or lightmap state
9045 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9048 // render the range of surfaces
9049 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9051 R_FrameData_ReturnToMark();
9054 float locboxvertex3f[6*4*3] =
9056 1,0,1, 1,0,0, 1,1,0, 1,1,1,
9057 0,1,1, 0,1,0, 0,0,0, 0,0,1,
9058 1,1,1, 1,1,0, 0,1,0, 0,1,1,
9059 0,0,1, 0,0,0, 1,0,0, 1,0,1,
9060 0,0,1, 1,0,1, 1,1,1, 0,1,1,
9061 1,0,0, 0,0,0, 0,1,0, 1,1,0
9064 unsigned short locboxelements[6*2*3] =
9074 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9077 cl_locnode_t *loc = (cl_locnode_t *)ent;
9079 float vertex3f[6*4*3];
9081 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9082 GL_DepthMask(false);
9083 GL_DepthRange(0, 1);
9084 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9086 GL_CullFace(GL_NONE);
9087 R_EntityMatrix(&identitymatrix);
9089 // R_Mesh_ResetTextureState();
9092 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9093 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9094 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9095 surfacelist[0] < 0 ? 0.5f : 0.125f);
9097 if (VectorCompare(loc->mins, loc->maxs))
9099 VectorSet(size, 2, 2, 2);
9100 VectorMA(loc->mins, -0.5f, size, mins);
9104 VectorCopy(loc->mins, mins);
9105 VectorSubtract(loc->maxs, loc->mins, size);
9108 for (i = 0;i < 6*4*3;)
9109 for (j = 0;j < 3;j++, i++)
9110 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9112 R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9113 R_SetupShader_Generic_NoTexture(false, false);
9114 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9117 void R_DrawLocs(void)
9120 cl_locnode_t *loc, *nearestloc;
9122 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9123 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9125 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9126 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9130 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9132 if (decalsystem->decals)
9133 Mem_Free(decalsystem->decals);
9134 memset(decalsystem, 0, sizeof(*decalsystem));
9137 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)
9143 // expand or initialize the system
9144 if (decalsystem->maxdecals <= decalsystem->numdecals)
9146 decalsystem_t old = *decalsystem;
9147 qbool useshortelements;
9148 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9149 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9150 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)));
9151 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9152 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9153 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9154 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9155 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9156 if (decalsystem->numdecals)
9157 memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9159 Mem_Free(old.decals);
9160 for (i = 0;i < decalsystem->maxdecals*3;i++)
9161 decalsystem->element3i[i] = i;
9162 if (useshortelements)
9163 for (i = 0;i < decalsystem->maxdecals*3;i++)
9164 decalsystem->element3s[i] = i;
9167 // grab a decal and search for another free slot for the next one
9168 decals = decalsystem->decals;
9169 decal = decalsystem->decals + (i = decalsystem->freedecal++);
9170 for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9172 decalsystem->freedecal = i;
9173 if (decalsystem->numdecals <= i)
9174 decalsystem->numdecals = i + 1;
9176 // initialize the decal
9178 decal->triangleindex = triangleindex;
9179 decal->surfaceindex = surfaceindex;
9180 decal->decalsequence = decalsequence;
9181 decal->color4f[0][0] = c0[0];
9182 decal->color4f[0][1] = c0[1];
9183 decal->color4f[0][2] = c0[2];
9184 decal->color4f[0][3] = 1;
9185 decal->color4f[1][0] = c1[0];
9186 decal->color4f[1][1] = c1[1];
9187 decal->color4f[1][2] = c1[2];
9188 decal->color4f[1][3] = 1;
9189 decal->color4f[2][0] = c2[0];
9190 decal->color4f[2][1] = c2[1];
9191 decal->color4f[2][2] = c2[2];
9192 decal->color4f[2][3] = 1;
9193 decal->vertex3f[0][0] = v0[0];
9194 decal->vertex3f[0][1] = v0[1];
9195 decal->vertex3f[0][2] = v0[2];
9196 decal->vertex3f[1][0] = v1[0];
9197 decal->vertex3f[1][1] = v1[1];
9198 decal->vertex3f[1][2] = v1[2];
9199 decal->vertex3f[2][0] = v2[0];
9200 decal->vertex3f[2][1] = v2[1];
9201 decal->vertex3f[2][2] = v2[2];
9202 decal->texcoord2f[0][0] = t0[0];
9203 decal->texcoord2f[0][1] = t0[1];
9204 decal->texcoord2f[1][0] = t1[0];
9205 decal->texcoord2f[1][1] = t1[1];
9206 decal->texcoord2f[2][0] = t2[0];
9207 decal->texcoord2f[2][1] = t2[1];
9208 TriangleNormal(v0, v1, v2, decal->plane);
9209 VectorNormalize(decal->plane);
9210 decal->plane[3] = DotProduct(v0, decal->plane);
9213 extern cvar_t cl_decals_bias;
9214 extern cvar_t cl_decals_models;
9215 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9216 // baseparms, parms, temps
9217 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, qbool dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9222 const float *vertex3f;
9223 const float *normal3f;
9225 float points[2][9][3];
9232 e = rsurface.modelelement3i + 3*triangleindex;
9234 vertex3f = rsurface.modelvertex3f;
9235 normal3f = rsurface.modelnormal3f;
9239 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9241 index = 3*e[cornerindex];
9242 VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9247 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9249 index = 3*e[cornerindex];
9250 VectorCopy(vertex3f + index, v[cornerindex]);
9255 //TriangleNormal(v[0], v[1], v[2], normal);
9256 //if (DotProduct(normal, localnormal) < 0.0f)
9258 // clip by each of the box planes formed from the projection matrix
9259 // if anything survives, we emit the decal
9260 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]);
9263 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]);
9266 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]);
9269 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]);
9272 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]);
9275 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]);
9278 // some part of the triangle survived, so we have to accept it...
9281 // dynamic always uses the original triangle
9283 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9285 index = 3*e[cornerindex];
9286 VectorCopy(vertex3f + index, v[cornerindex]);
9289 for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9291 // convert vertex positions to texcoords
9292 Matrix4x4_Transform(projection, v[cornerindex], temp);
9293 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9294 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9295 // calculate distance fade from the projection origin
9296 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9297 f = bound(0.0f, f, 1.0f);
9298 c[cornerindex][0] = r * f;
9299 c[cornerindex][1] = g * f;
9300 c[cornerindex][2] = b * f;
9301 c[cornerindex][3] = 1.0f;
9302 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9305 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);
9307 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9308 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);
9310 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)
9312 matrix4x4_t projection;
9313 decalsystem_t *decalsystem;
9316 const msurface_t *surface;
9317 const msurface_t *surfaces;
9318 const int *surfacelist;
9319 const texture_t *texture;
9322 int surfacelistindex;
9325 float localorigin[3];
9326 float localnormal[3];
9334 int bih_triangles_count;
9335 int bih_triangles[256];
9336 int bih_surfaces[256];
9338 decalsystem = &ent->decalsystem;
9340 if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9342 R_DecalSystem_Reset(&ent->decalsystem);
9346 if (!model->brush.data_leafs && !cl_decals_models.integer)
9348 if (decalsystem->model)
9349 R_DecalSystem_Reset(decalsystem);
9353 if (decalsystem->model != model)
9354 R_DecalSystem_Reset(decalsystem);
9355 decalsystem->model = model;
9357 RSurf_ActiveModelEntity(ent, true, false, false);
9359 Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9360 Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9361 VectorNormalize(localnormal);
9362 localsize = worldsize*rsurface.inversematrixscale;
9363 localmins[0] = localorigin[0] - localsize;
9364 localmins[1] = localorigin[1] - localsize;
9365 localmins[2] = localorigin[2] - localsize;
9366 localmaxs[0] = localorigin[0] + localsize;
9367 localmaxs[1] = localorigin[1] + localsize;
9368 localmaxs[2] = localorigin[2] + localsize;
9370 //VectorCopy(localnormal, planes[4]);
9371 //VectorVectors(planes[4], planes[2], planes[0]);
9372 AnglesFromVectors(angles, localnormal, NULL, false);
9373 AngleVectors(angles, planes[0], planes[2], planes[4]);
9374 VectorNegate(planes[0], planes[1]);
9375 VectorNegate(planes[2], planes[3]);
9376 VectorNegate(planes[4], planes[5]);
9377 planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9378 planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9379 planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9380 planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9381 planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9382 planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9387 matrix4x4_t forwardprojection;
9388 Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9389 Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9394 float projectionvector[4][3];
9395 VectorScale(planes[0], ilocalsize, projectionvector[0]);
9396 VectorScale(planes[2], ilocalsize, projectionvector[1]);
9397 VectorScale(planes[4], ilocalsize, projectionvector[2]);
9398 projectionvector[0][0] = planes[0][0] * ilocalsize;
9399 projectionvector[0][1] = planes[1][0] * ilocalsize;
9400 projectionvector[0][2] = planes[2][0] * ilocalsize;
9401 projectionvector[1][0] = planes[0][1] * ilocalsize;
9402 projectionvector[1][1] = planes[1][1] * ilocalsize;
9403 projectionvector[1][2] = planes[2][1] * ilocalsize;
9404 projectionvector[2][0] = planes[0][2] * ilocalsize;
9405 projectionvector[2][1] = planes[1][2] * ilocalsize;
9406 projectionvector[2][2] = planes[2][2] * ilocalsize;
9407 projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9408 projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9409 projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9410 Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9414 dynamic = model->surfmesh.isanimated;
9415 numsurfacelist = model->nummodelsurfaces;
9416 surfacelist = model->sortedmodelsurfaces;
9417 surfaces = model->data_surfaces;
9420 bih_triangles_count = -1;
9423 if(model->render_bih.numleafs)
9424 bih = &model->render_bih;
9425 else if(model->collision_bih.numleafs)
9426 bih = &model->collision_bih;
9429 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9430 if(bih_triangles_count == 0)
9432 if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9434 if(bih_triangles_count > 0)
9436 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9438 surfaceindex = bih_surfaces[triangleindex];
9439 surface = surfaces + surfaceindex;
9440 texture = surface->texture;
9443 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9445 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9447 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9452 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9454 surfaceindex = surfacelist[surfacelistindex];
9455 surface = surfaces + surfaceindex;
9456 // check cull box first because it rejects more than any other check
9457 if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9459 // skip transparent surfaces
9460 texture = surface->texture;
9463 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9465 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9467 numtriangles = surface->num_triangles;
9468 for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9469 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9474 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9475 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)
9477 int renderentityindex;
9480 entity_render_t *ent;
9482 worldmins[0] = worldorigin[0] - worldsize;
9483 worldmins[1] = worldorigin[1] - worldsize;
9484 worldmins[2] = worldorigin[2] - worldsize;
9485 worldmaxs[0] = worldorigin[0] + worldsize;
9486 worldmaxs[1] = worldorigin[1] + worldsize;
9487 worldmaxs[2] = worldorigin[2] + worldsize;
9489 R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9491 for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9493 ent = r_refdef.scene.entities[renderentityindex];
9494 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9497 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9501 typedef struct r_decalsystem_splatqueue_s
9508 unsigned int decalsequence;
9510 r_decalsystem_splatqueue_t;
9512 int r_decalsystem_numqueued = 0;
9513 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9515 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)
9517 r_decalsystem_splatqueue_t *queue;
9519 if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9522 queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9523 VectorCopy(worldorigin, queue->worldorigin);
9524 VectorCopy(worldnormal, queue->worldnormal);
9525 Vector4Set(queue->color, r, g, b, a);
9526 Vector4Set(queue->tcrange, s1, t1, s2, t2);
9527 queue->worldsize = worldsize;
9528 queue->decalsequence = cl.decalsequence++;
9531 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9534 r_decalsystem_splatqueue_t *queue;
9536 for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9537 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);
9538 r_decalsystem_numqueued = 0;
9541 extern cvar_t cl_decals_max;
9542 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9545 decalsystem_t *decalsystem = &ent->decalsystem;
9547 unsigned int killsequence;
9552 if (!decalsystem->numdecals)
9555 if (r_showsurfaces.integer)
9558 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9560 R_DecalSystem_Reset(decalsystem);
9564 killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9565 lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9567 if (decalsystem->lastupdatetime)
9568 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9571 decalsystem->lastupdatetime = r_refdef.scene.time;
9572 numdecals = decalsystem->numdecals;
9574 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9576 if (decal->color4f[0][3])
9578 decal->lived += frametime;
9579 if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9581 memset(decal, 0, sizeof(*decal));
9582 if (decalsystem->freedecal > i)
9583 decalsystem->freedecal = i;
9587 decal = decalsystem->decals;
9588 while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9591 // collapse the array by shuffling the tail decals into the gaps
9594 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9595 decalsystem->freedecal++;
9596 if (decalsystem->freedecal == numdecals)
9598 decal[decalsystem->freedecal] = decal[--numdecals];
9601 decalsystem->numdecals = numdecals;
9605 // if there are no decals left, reset decalsystem
9606 R_DecalSystem_Reset(decalsystem);
9610 extern skinframe_t *decalskinframe;
9611 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9614 decalsystem_t *decalsystem = &ent->decalsystem;
9623 const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9626 numdecals = decalsystem->numdecals;
9630 if (r_showsurfaces.integer)
9633 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9635 R_DecalSystem_Reset(decalsystem);
9639 // if the model is static it doesn't matter what value we give for
9640 // wantnormals and wanttangents, so this logic uses only rules applicable
9641 // to a model, knowing that they are meaningless otherwise
9642 RSurf_ActiveModelEntity(ent, false, false, false);
9644 decalsystem->lastupdatetime = r_refdef.scene.time;
9646 faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9648 // update vertex positions for animated models
9649 v3f = decalsystem->vertex3f;
9650 c4f = decalsystem->color4f;
9651 t2f = decalsystem->texcoord2f;
9652 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9654 if (!decal->color4f[0][3])
9657 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9661 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9664 // update color values for fading decals
9665 if (decal->lived >= cl_decals_time.value)
9666 alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9670 c4f[ 0] = decal->color4f[0][0] * alpha;
9671 c4f[ 1] = decal->color4f[0][1] * alpha;
9672 c4f[ 2] = decal->color4f[0][2] * alpha;
9674 c4f[ 4] = decal->color4f[1][0] * alpha;
9675 c4f[ 5] = decal->color4f[1][1] * alpha;
9676 c4f[ 6] = decal->color4f[1][2] * alpha;
9678 c4f[ 8] = decal->color4f[2][0] * alpha;
9679 c4f[ 9] = decal->color4f[2][1] * alpha;
9680 c4f[10] = decal->color4f[2][2] * alpha;
9683 t2f[0] = decal->texcoord2f[0][0];
9684 t2f[1] = decal->texcoord2f[0][1];
9685 t2f[2] = decal->texcoord2f[1][0];
9686 t2f[3] = decal->texcoord2f[1][1];
9687 t2f[4] = decal->texcoord2f[2][0];
9688 t2f[5] = decal->texcoord2f[2][1];
9690 // update vertex positions for animated models
9691 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9693 e = rsurface.modelelement3i + 3*decal->triangleindex;
9694 VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9695 VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9696 VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9700 VectorCopy(decal->vertex3f[0], v3f);
9701 VectorCopy(decal->vertex3f[1], v3f + 3);
9702 VectorCopy(decal->vertex3f[2], v3f + 6);
9705 if (r_refdef.fogenabled)
9707 alpha = RSurf_FogVertex(v3f);
9708 VectorScale(c4f, alpha, c4f);
9709 alpha = RSurf_FogVertex(v3f + 3);
9710 VectorScale(c4f + 4, alpha, c4f + 4);
9711 alpha = RSurf_FogVertex(v3f + 6);
9712 VectorScale(c4f + 8, alpha, c4f + 8);
9723 r_refdef.stats[r_stat_drawndecals] += numtris;
9725 // now render the decals all at once
9726 // (this assumes they all use one particle font texture!)
9727 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);
9728 // R_Mesh_ResetTextureState();
9729 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9730 GL_DepthMask(false);
9731 GL_DepthRange(0, 1);
9732 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9734 GL_CullFace(GL_NONE);
9735 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9736 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9737 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9741 static void R_DrawModelDecals(void)
9745 // fade faster when there are too many decals
9746 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9747 for (i = 0;i < r_refdef.scene.numentities;i++)
9748 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9750 R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9751 for (i = 0;i < r_refdef.scene.numentities;i++)
9752 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9753 R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9755 R_DecalSystem_ApplySplatEntitiesQueue();
9757 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9758 for (i = 0;i < r_refdef.scene.numentities;i++)
9759 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9761 r_refdef.stats[r_stat_totaldecals] += numdecals;
9763 if (r_showsurfaces.integer || !r_drawdecals.integer)
9766 R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9768 for (i = 0;i < r_refdef.scene.numentities;i++)
9770 if (!r_refdef.viewcache.entityvisible[i])
9772 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9773 R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9777 static void R_DrawDebugModel(void)
9779 entity_render_t *ent = rsurface.entity;
9780 int i, j, flagsmask;
9781 const msurface_t *surface;
9782 model_t *model = ent->model;
9784 if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9787 if (r_showoverdraw.value > 0)
9789 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9790 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9791 R_SetupShader_Generic_NoTexture(false, false);
9792 GL_DepthTest(false);
9793 GL_DepthMask(false);
9794 GL_DepthRange(0, 1);
9795 GL_BlendFunc(GL_ONE, GL_ONE);
9796 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9798 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9800 rsurface.texture = R_GetCurrentTexture(surface->texture);
9801 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9803 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9804 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9805 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9806 GL_Color(c, 0, 0, 1.0f);
9807 else if (ent == r_refdef.scene.worldentity)
9808 GL_Color(c, c, c, 1.0f);
9810 GL_Color(0, c, 0, 1.0f);
9811 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9815 rsurface.texture = NULL;
9818 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9820 // R_Mesh_ResetTextureState();
9821 R_SetupShader_Generic_NoTexture(false, false);
9822 GL_DepthRange(0, 1);
9823 GL_DepthTest(!r_showdisabledepthtest.integer);
9824 GL_DepthMask(false);
9825 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9827 if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9831 qbool cullbox = false;
9832 const q3mbrush_t *brush;
9833 const bih_t *bih = &model->collision_bih;
9834 const bih_leaf_t *bihleaf;
9835 float vertex3f[3][3];
9836 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9837 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9839 if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9841 switch (bihleaf->type)
9844 brush = model->brush.data_brushes + bihleaf->itemindex;
9845 if (brush->colbrushf && brush->colbrushf->numtriangles)
9847 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);
9848 R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9849 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9852 case BIH_COLLISIONTRIANGLE:
9853 triangleindex = bihleaf->itemindex;
9854 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9855 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9856 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9857 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);
9858 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9859 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9861 case BIH_RENDERTRIANGLE:
9862 triangleindex = bihleaf->itemindex;
9863 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9864 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9865 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9866 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);
9867 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9868 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9874 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9877 if (r_showtris.value > 0 && qglPolygonMode)
9879 if (r_showdisabledepthtest.integer)
9881 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9882 GL_DepthMask(false);
9886 GL_BlendFunc(GL_ONE, GL_ZERO);
9889 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9890 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9892 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9894 rsurface.texture = R_GetCurrentTexture(surface->texture);
9895 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9897 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9898 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9899 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9900 else if (ent == r_refdef.scene.worldentity)
9901 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9903 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9904 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9908 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9909 rsurface.texture = NULL;
9913 // FIXME! implement r_shownormals with just triangles
9914 if (r_shownormals.value != 0 && qglBegin)
9918 if (r_showdisabledepthtest.integer)
9920 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9921 GL_DepthMask(false);
9925 GL_BlendFunc(GL_ONE, GL_ZERO);
9928 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9930 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9932 rsurface.texture = R_GetCurrentTexture(surface->texture);
9933 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9935 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9937 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9939 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9941 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9942 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9943 qglVertex3f(v[0], v[1], v[2]);
9944 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9945 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9946 qglVertex3f(v[0], v[1], v[2]);
9949 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9951 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9953 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9954 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9955 qglVertex3f(v[0], v[1], v[2]);
9956 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9957 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9958 qglVertex3f(v[0], v[1], v[2]);
9961 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9963 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9965 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9966 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9967 qglVertex3f(v[0], v[1], v[2]);
9968 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9969 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9970 qglVertex3f(v[0], v[1], v[2]);
9973 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9975 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9977 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9978 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9979 qglVertex3f(v[0], v[1], v[2]);
9980 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9981 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9982 qglVertex3f(v[0], v[1], v[2]);
9989 rsurface.texture = NULL;
9995 int r_maxsurfacelist = 0;
9996 const msurface_t **r_surfacelist = NULL;
9997 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
9999 int i, j, flagsmask;
10000 model_t *model = ent->model;
10001 msurface_t *surfaces;
10002 unsigned char *update;
10003 int numsurfacelist = 0;
10007 if (r_maxsurfacelist < model->num_surfaces)
10009 r_maxsurfacelist = model->num_surfaces;
10011 Mem_Free((msurface_t **)r_surfacelist);
10012 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10015 if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10016 RSurf_ActiveModelEntity(ent, false, false, false);
10018 RSurf_ActiveModelEntity(ent, true, true, true);
10019 else if (depthonly)
10020 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10022 RSurf_ActiveModelEntity(ent, true, true, false);
10024 surfaces = model->data_surfaces;
10025 update = model->brushq1.lightmapupdateflags;
10027 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10031 R_DrawDebugModel();
10032 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10036 // check if this is an empty model
10037 if (model->nummodelsurfaces == 0)
10040 rsurface.lightmaptexture = NULL;
10041 rsurface.deluxemaptexture = NULL;
10042 rsurface.uselightmaptexture = false;
10043 rsurface.texture = NULL;
10044 rsurface.rtlight = NULL;
10045 numsurfacelist = 0;
10047 // add visible surfaces to draw list
10048 if (ent == r_refdef.scene.worldentity)
10050 // for the world entity, check surfacevisible
10051 for (i = 0;i < model->nummodelsurfaces;i++)
10053 j = model->sortedmodelsurfaces[i];
10054 if (r_refdef.viewcache.world_surfacevisible[j])
10055 r_surfacelist[numsurfacelist++] = surfaces + j;
10058 // don't do anything if there were no surfaces added (none of the world entity is visible)
10059 if (!numsurfacelist)
10061 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10067 // for ui we have to preserve the order of surfaces (not using sortedmodelsurfaces)
10068 for (i = 0; i < model->nummodelsurfaces; i++)
10069 r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10073 // add all surfaces
10074 for (i = 0; i < model->nummodelsurfaces; i++)
10075 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10079 * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10080 * using style chains because most styles do not change on most frames, and most
10081 * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10082 * break this rule and animate most surfaces.
10084 if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10086 model_brush_lightstyleinfo_t *style;
10088 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10089 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10091 if (style->value != r_refdef.scene.lightstylevalue[style->style])
10093 int* list = style->surfacelist;
10094 style->value = r_refdef.scene.lightstylevalue[style->style];
10095 // Value changed - mark the surfaces belonging to this style chain as dirty
10096 for (j = 0; j < style->numsurfaces; j++)
10097 update[list[j]] = true;
10100 // Now check if update flags are set on any surfaces that are visible
10101 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10104 * We can do less frequent texture uploads (approximately 10hz for animated
10105 * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10106 * For optimal efficiency, this includes the submodels of the worldmodel, so we
10107 * use model->num_surfaces, not nummodelsurfaces.
10109 for (i = 0; i < model->num_surfaces;i++)
10111 R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10115 for (i = 0; i < numsurfacelist; i++)
10116 if (update[r_surfacelist[i] - surfaces])
10117 R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10121 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10123 // add to stats if desired
10124 if (r_speeds.integer && !skysurfaces && !depthonly)
10126 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10127 for (j = 0;j < numsurfacelist;j++)
10128 r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10131 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10134 void R_DebugLine(vec3_t start, vec3_t end)
10136 model_t *mod = CL_Mesh_UI();
10138 int e0, e1, e2, e3;
10139 float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10140 float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10141 float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10144 // transform to screen coords first
10145 Vector4Set(w[0], start[0], start[1], start[2], 1);
10146 Vector4Set(w[1], end[0], end[1], end[2], 1);
10147 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10148 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10149 x1 = s[0][0] * vid_conwidth.value / vid.width;
10150 y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10151 x2 = s[1][0] * vid_conwidth.value / vid.width;
10152 y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10153 //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10155 // add the line to the UI mesh for drawing later
10157 // width is measured in real pixels
10158 if (fabs(x2 - x1) > fabs(y2 - y1))
10161 offsety = 0.5f * width * vid_conheight.value / vid.height;
10165 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10168 surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), true);
10169 e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10170 e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10171 e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10172 e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10173 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10174 Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10179 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10181 static texture_t texture;
10183 // fake enough texture and surface state to render this geometry
10185 texture.update_lastrenderframe = -1; // regenerate this texture
10186 texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10187 texture.basealpha = 1.0f;
10188 texture.currentskinframe = skinframe;
10189 texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10190 texture.offsetmapping = OFFSETMAPPING_OFF;
10191 texture.offsetscale = 1;
10192 texture.specularscalemod = 1;
10193 texture.specularpowermod = 1;
10194 texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10196 R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10199 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10201 static msurface_t surface;
10202 const msurface_t *surfacelist = &surface;
10204 // fake enough texture and surface state to render this geometry
10205 surface.texture = texture;
10206 surface.num_triangles = numtriangles;
10207 surface.num_firsttriangle = firsttriangle;
10208 surface.num_vertices = numvertices;
10209 surface.num_firstvertex = firstvertex;
10212 rsurface.texture = R_GetCurrentTexture(surface.texture);
10213 rsurface.lightmaptexture = NULL;
10214 rsurface.deluxemaptexture = NULL;
10215 rsurface.uselightmaptexture = false;
10216 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);