X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=76931c357033927c4a79cf27b092438d881776ba;hb=5927c6f5fe5fd0fcd20072ce6679d9e1c7b4212e;hp=9a9419f531f656164c097e007bc6c4a30e373fc8;hpb=331e31efc820e28ca6bbc089ffe33d78962fbfe3;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index 9a9419f5..76931c35 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -44,14 +44,15 @@ static qboolean r_loadgloss; qboolean r_loadfog; static qboolean r_loaddds; static qboolean r_savedds; +static qboolean r_gpuskeletal; // // screen size info // r_refdef_t r_refdef; -cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended"}; -cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended"}; +cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"}; +cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"}; cvar_t r_motionblur_averaging = {CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"}; cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"}; cvar_t r_motionblur_minblur = {CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"}; @@ -77,6 +78,8 @@ cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip pla cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"}; cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"}; cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"}; +cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"}; +cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"}; cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"}; cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"}; cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"}; @@ -118,6 +121,7 @@ cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlightin cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"}; cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"}; cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "1", "increases shadowmap quality (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."}; +cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."}; cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"}; cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"}; cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"}; @@ -130,6 +134,8 @@ cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"}; cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"}; cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"}; +cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9 +cvar_t r_celoutlines = {CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"}; cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"}; @@ -147,6 +153,7 @@ cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"}; static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"}; +cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"}; cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"}; cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"}; cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"}; @@ -156,6 +163,7 @@ cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_SAVE, "r_viewscale_fpsscaling_ste cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"}; cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"}; +cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"}; cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"}; cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"}; cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"}; @@ -183,6 +191,7 @@ cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "h cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"}; cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"}; cvar_t r_water_hideplayer = {CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"}; +cvar_t r_water_fbo = {CVAR_SAVE, "r_water_fbo", "1", "enables use of render to texture for water effects, otherwise copy to texture is used (slower)"}; cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"}; cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"}; @@ -191,16 +200,16 @@ cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll aro cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"}; cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"}; + cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"}; cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"}; cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"}; cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"}; cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"}; +cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"}; -cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"}; cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"}; cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"}; -cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivalent to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"}; cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"}; cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"}; cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"}; @@ -214,56 +223,41 @@ cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"}; -cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"}; +cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"}; cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; +cvar_t r_batch_multidraw = {CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"}; +cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"}; +cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"}; +cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"}; + cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"}; cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"}; -cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer."}; +cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."}; cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"}; +cvar_t r_buffermegs[R_BUFFERDATA_COUNT] = +{ + {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"}, + {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"}, + {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"}, + {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"}, +}; extern cvar_t v_glslgamma; extern cvar_t v_glslgamma_2d; extern qboolean v_flipped_state; -static struct r_bloomstate_s -{ - qboolean enabled; - qboolean hdr; - - int bloomwidth, bloomheight; - - textype_t texturetype; - int viewfbo; // used to check if r_viewfbo cvar has changed - - int fbo_framebuffer; // non-zero if r_viewfbo is enabled and working - rtexture_t *texture_framebuffercolor; // non-NULL if fbo_screen is non-zero - rtexture_t *texture_framebufferdepth; // non-NULL if fbo_screen is non-zero - - int screentexturewidth, screentextureheight; - rtexture_t *texture_screen; /// \note also used for motion blur if enabled! - - int bloomtexturewidth, bloomtextureheight; - rtexture_t *texture_bloom; - - // arrays for rendering the screen passes - float screentexcoord2f[8]; - float bloomtexcoord2f[8]; - float offsettexcoord2f[8]; - - r_viewport_t viewport; -} -r_bloomstate; - -r_waterstate_t r_waterstate; +r_framebufferstate_t r_fb; /// shadow volume bsp struct with automatically growing nodes buffer svbsp_t r_svbsp; +int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT + rtexture_t *r_texture_blanknormalmap; rtexture_t *r_texture_white; rtexture_t *r_texture_grey128; @@ -619,13 +613,17 @@ static void R_BuildFogHeightTexture(void) //======================================================================================================================================================= -static const char *builtinshaderstring = +static const char *builtinshaderstrings[] = +{ #include "shader_glsl.h" -; +0 +}; -const char *builtinhlslshaderstring = +const char *builtinhlslshaderstrings[] = +{ #include "shader_hlsl.h" -; +0 +}; char *glslshaderstring = NULL; char *hlslshaderstring = NULL; @@ -641,9 +639,7 @@ shaderpermutationinfo_t; typedef struct shadermodeinfo_s { - const char *vertexfilename; - const char *geometryfilename; - const char *fragmentfilename; + const char *filename; const char *pretext; const char *name; } @@ -671,63 +667,61 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] = {"#define USEOFFSETMAPPING\n", " offsetmapping"}, {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"}, {"#define USESHADOWMAP2D\n", " shadowmap2d"}, - {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"}, - {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"}, - {"#define USESHADOWSAMPLER\n", " shadowsampler"}, - {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, + {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm {"#define USESHADOWMAPORTHO\n", " shadowmaportho"}, {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"}, {"#define USEALPHAKILL\n", " alphakill"}, {"#define USEREFLECTCUBE\n", " reflectcube"}, {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"}, {"#define USEBOUNCEGRID\n", " bouncegrid"}, - {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, + {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm {"#define USETRIPPY\n", " trippy"}, + {"#define USEDEPTHRGB\n", " depthrgb"}, + {"#define USEALPHAGENVERTEX\n", " alphagenvertex"}, + {"#define USESKELETAL\n", " skeletal"} }; // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS! shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] = { - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FAKELIGHT\n", " fakelight"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"}, - {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"}, + {"glsl/default.glsl", "#define MODE_GENERIC\n", " generic"}, + {"glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"}, + {"glsl/default.glsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"}, + {"glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"}, + {"glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"}, + {"glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"}, + {"glsl/default.glsl", "#define MODE_FAKELIGHT\n", " fakelight"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"}, + {"glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"}, + {"glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"}, + {"glsl/default.glsl", "#define MODE_WATER\n", " water"}, + {"glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"}, + {"glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"}, }; shadermodeinfo_t hlslshadermodeinfo[SHADERMODE_COUNT] = { - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_GENERIC\n", " generic"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_POSTPROCESS\n", " postprocess"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_FLATCOLOR\n", " flatcolor"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTMAP\n", " lightmap"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTSOURCE\n", " lightsource"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_REFRACTION\n", " refraction"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_WATER\n", " water"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_SHOWDEPTH\n", " showdepth"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"}, - {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"}, + {"hlsl/default.hlsl", "#define MODE_GENERIC\n", " generic"}, + {"hlsl/default.hlsl", "#define MODE_POSTPROCESS\n", " postprocess"}, + {"hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"}, + {"hlsl/default.hlsl", "#define MODE_FLATCOLOR\n", " flatcolor"}, + {"hlsl/default.hlsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTMAP\n", " lightmap"}, + {"hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTSOURCE\n", " lightsource"}, + {"hlsl/default.hlsl", "#define MODE_REFRACTION\n", " refraction"}, + {"hlsl/default.hlsl", "#define MODE_WATER\n", " water"}, + {"hlsl/default.hlsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"}, + {"hlsl/default.hlsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"}, }; struct r_glsl_permutation_s; @@ -766,7 +760,6 @@ typedef struct r_glsl_permutation_s int tex_Texture_Reflection; int tex_Texture_ShadowMap2D; int tex_Texture_CubeProjection; - int tex_Texture_ScreenDepth; int tex_Texture_ScreenNormalMap; int tex_Texture_ScreenDiffuse; int tex_Texture_ScreenSpecular; @@ -797,7 +790,6 @@ typedef struct r_glsl_permutation_s int loc_Texture_Reflection; int loc_Texture_ShadowMap2D; int loc_Texture_CubeProjection; - int loc_Texture_ScreenDepth; int loc_Texture_ScreenNormalMap; int loc_Texture_ScreenDiffuse; int loc_Texture_ScreenSpecular; @@ -843,6 +835,7 @@ typedef struct r_glsl_permutation_s int loc_ShadowMap_Parameters; int loc_ShadowMap_TextureScale; int loc_SpecularPower; + int loc_Skeletal_Transform12; int loc_UserVec1; int loc_UserVec2; int loc_UserVec3; @@ -861,6 +854,10 @@ typedef struct r_glsl_permutation_s int loc_NormalmapScrollBlend; int loc_BounceGridMatrix; int loc_BounceGridIntensity; + /// uniform block bindings + int ubibind_Skeletal_Transform12_UniformBlock; + /// uniform block indices + int ubiloc_Skeletal_Transform12_UniformBlock; } r_glsl_permutation_t; @@ -879,14 +876,22 @@ enum SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping + SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1 + SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2 + SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler + SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math) + SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines) }; -#define SHADERSTATICPARMS_COUNT 8 +#define SHADERSTATICPARMS_COUNT 13 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT]; static int shaderstaticparms_count = 0; static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0}; #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F)) + +extern qboolean r_shadow_shadowmapsampler; +extern int r_shadow_shadowmappcf; qboolean R_CompileShader_CheckStaticParms(void) { static int r_compileshader_staticparms_save[1]; @@ -913,6 +918,18 @@ qboolean R_CompileShader_CheckStaticParms(void) } if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0) R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD); + + if (r_shadow_shadowmapsampler) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER); + if (r_shadow_shadowmappcf > 1) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2); + else if (r_shadow_shadowmappcf) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1); + if (r_celshading.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING); + if (r_celoutlines.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES); + return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0; } @@ -921,7 +938,7 @@ qboolean R_CompileShader_CheckStaticParms(void) shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \ else \ shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n" -void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation) +static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation) { shaderstaticparms_count = 0; @@ -934,6 +951,11 @@ void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation) R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES"); } /// information about each possible shader permutation @@ -968,25 +990,68 @@ static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, unsigned return p; } -static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice) +static char *R_ShaderStrCat(const char **strings) +{ + char *string, *s; + const char **p = strings; + const char *t; + size_t len = 0; + for (p = strings;(t = *p);p++) + len += strlen(t); + len++; + s = string = (char *)Mem_Alloc(r_main_mempool, len); + len = 0; + for (p = strings;(t = *p);p++) + { + len = strlen(t); + memcpy(s, t, len); + s += len; + } + *s = 0; + return string; +} + +static char *R_GetShaderText(const char *filename, qboolean printfromdisknotice, qboolean builtinonly) { char *shaderstring; if (!filename || !filename[0]) return NULL; + // LordHavoc: note that FS_LoadFile appends a 0 byte to make it a valid string, so does R_ShaderStrCat if (!strcmp(filename, "glsl/default.glsl")) { + if (builtinonly) + return R_ShaderStrCat(builtinshaderstrings); if (!glslshaderstring) { glslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); if (glslshaderstring) Con_DPrintf("Loading shaders from file %s...\n", filename); else - glslshaderstring = (char *)builtinshaderstring; + glslshaderstring = R_ShaderStrCat(builtinshaderstrings); } shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(glslshaderstring) + 1); memcpy(shaderstring, glslshaderstring, strlen(glslshaderstring) + 1); return shaderstring; } + if (!strcmp(filename, "hlsl/default.hlsl")) + { + if (builtinonly) + return R_ShaderStrCat(builtinhlslshaderstrings); + if (!hlslshaderstring) + { + hlslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); + if (hlslshaderstring) + Con_DPrintf("Loading shaders from file %s...\n", filename); + else + hlslshaderstring = R_ShaderStrCat(builtinhlslshaderstrings); + } + shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(hlslshaderstring) + 1); + memcpy(shaderstring, hlslshaderstring, strlen(hlslshaderstring) + 1); + return shaderstring; + } + // we don't have builtin strings for any other files + if (builtinonly) + return NULL; shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); if (shaderstring) { @@ -1000,16 +1065,17 @@ static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice) static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, unsigned int permutation) { int i; + int ubibind; int sampler; shadermodeinfo_t *modeinfo = glslshadermodeinfo + mode; - char *vertexstring, *geometrystring, *fragmentstring; + char *sourcestring; char permutationname[256]; int vertstrings_count = 0; int geomstrings_count = 0; int fragstrings_count = 0; - const char *vertstrings_list[32+3+SHADERSTATICPARMS_COUNT+1]; - const char *geomstrings_list[32+3+SHADERSTATICPARMS_COUNT+1]; - const char *fragstrings_list[32+3+SHADERSTATICPARMS_COUNT+1]; + const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; if (p->compiled) return; @@ -1017,14 +1083,22 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode p->program = 0; permutationname[0] = 0; - vertexstring = R_GLSL_GetText(modeinfo->vertexfilename, true); - geometrystring = R_GLSL_GetText(modeinfo->geometryfilename, false); - fragmentstring = R_GLSL_GetText(modeinfo->fragmentfilename, false); + sourcestring = R_GetShaderText(modeinfo->filename, true, false); - strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname)); + strlcat(permutationname, modeinfo->filename, sizeof(permutationname)); + // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object) + if(vid.support.glshaderversion >= 140) + { + vertstrings_list[vertstrings_count++] = "#version 140\n"; + geomstrings_list[geomstrings_count++] = "#version 140\n"; + fragstrings_list[fragstrings_count++] = "#version 140\n"; + vertstrings_list[vertstrings_count++] = "#define GLSL140\n"; + geomstrings_list[geomstrings_count++] = "#define GLSL140\n"; + fragstrings_list[fragstrings_count++] = "#define GLSL140\n"; + } // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad) - if(vid.support.gl20shaders130) + else if(vid.support.glshaderversion >= 130) { vertstrings_list[vertstrings_count++] = "#version 130\n"; geomstrings_list[geomstrings_count++] = "#version 130\n"; @@ -1075,17 +1149,9 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode fragstrings_count += shaderstaticparms_count; // now append the shader text itself - vertstrings_list[vertstrings_count++] = vertexstring; - geomstrings_list[geomstrings_count++] = geometrystring; - fragstrings_list[fragstrings_count++] = fragmentstring; - - // if any sources were NULL, clear the respective list - if (!vertexstring) - vertstrings_count = 0; - if (!geometrystring) - geomstrings_count = 0; - if (!fragmentstring) - fragstrings_count = 0; + vertstrings_list[vertstrings_count++] = sourcestring; + geomstrings_list[geomstrings_count++] = sourcestring; + fragstrings_list[fragstrings_count++] = sourcestring; // compile the shader program if (vertstrings_count + geomstrings_count + fragstrings_count) @@ -1097,6 +1163,26 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode // look up all the uniform variable names we care about, so we don't // have to look them up every time we set them +#if 0 + // debugging aid + { + GLint activeuniformindex = 0; + GLint numactiveuniforms = 0; + char uniformname[128]; + GLsizei uniformnamelength = 0; + GLint uniformsize = 0; + GLenum uniformtype = 0; + memset(uniformname, 0, sizeof(uniformname)); + qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms); + Con_Printf("Shader has %i uniforms\n", numactiveuniforms); + for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++) + { + qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname); + Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype); + } + } +#endif + p->loc_Texture_First = qglGetUniformLocation(p->program, "Texture_First"); p->loc_Texture_Second = qglGetUniformLocation(p->program, "Texture_Second"); p->loc_Texture_GammaRamps = qglGetUniformLocation(p->program, "Texture_GammaRamps"); @@ -1120,7 +1206,6 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode p->loc_Texture_Reflection = qglGetUniformLocation(p->program, "Texture_Reflection"); p->loc_Texture_ShadowMap2D = qglGetUniformLocation(p->program, "Texture_ShadowMap2D"); p->loc_Texture_CubeProjection = qglGetUniformLocation(p->program, "Texture_CubeProjection"); - p->loc_Texture_ScreenDepth = qglGetUniformLocation(p->program, "Texture_ScreenDepth"); p->loc_Texture_ScreenNormalMap = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap"); p->loc_Texture_ScreenDiffuse = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse"); p->loc_Texture_ScreenSpecular = qglGetUniformLocation(p->program, "Texture_ScreenSpecular"); @@ -1208,13 +1293,13 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode p->tex_Texture_Reflection = -1; p->tex_Texture_ShadowMap2D = -1; p->tex_Texture_CubeProjection = -1; - p->tex_Texture_ScreenDepth = -1; p->tex_Texture_ScreenNormalMap = -1; p->tex_Texture_ScreenDiffuse = -1; p->tex_Texture_ScreenSpecular = -1; p->tex_Texture_ReflectMask = -1; p->tex_Texture_ReflectCube = -1; p->tex_Texture_BounceGrid = -1; + // bind the texture samplers in use sampler = 0; if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;} if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;} @@ -1239,13 +1324,27 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode if (p->loc_Texture_Reflection >= 0) {p->tex_Texture_Reflection = sampler;qglUniform1i(p->loc_Texture_Reflection , sampler);sampler++;} if (p->loc_Texture_ShadowMap2D >= 0) {p->tex_Texture_ShadowMap2D = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D , sampler);sampler++;} if (p->loc_Texture_CubeProjection >= 0) {p->tex_Texture_CubeProjection = sampler;qglUniform1i(p->loc_Texture_CubeProjection , sampler);sampler++;} - if (p->loc_Texture_ScreenDepth >= 0) {p->tex_Texture_ScreenDepth = sampler;qglUniform1i(p->loc_Texture_ScreenDepth , sampler);sampler++;} if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;} if (p->loc_Texture_ScreenDiffuse >= 0) {p->tex_Texture_ScreenDiffuse = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse , sampler);sampler++;} if (p->loc_Texture_ScreenSpecular >= 0) {p->tex_Texture_ScreenSpecular = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular , sampler);sampler++;} if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;} if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;} if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;} + // get the uniform block indices so we can bind them +#ifndef USE_GLES2 /* FIXME: GLES3 only */ + if (vid.support.arb_uniform_buffer_object) + p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock"); + else +#endif + p->ubiloc_Skeletal_Transform12_UniformBlock = -1; + // clear the uniform block bindings + p->ubibind_Skeletal_Transform12_UniformBlock = -1; + // bind the uniform blocks in use + ubibind = 0; +#ifndef USE_GLES2 /* FIXME: GLES3 only */ + if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;} +#endif + // we're done compiling and setting up the shader, at least until it is used CHECKGLERROR Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler); } @@ -1253,15 +1352,11 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode Con_Printf("^1GLSL shader %s failed! some features may not work properly.\n", permutationname); // free the strings - if (vertexstring) - Mem_Free(vertexstring); - if (geometrystring) - Mem_Free(geometrystring); - if (fragmentstring) - Mem_Free(fragmentstring); + if (sourcestring) + Mem_Free(sourcestring); } -void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation) +static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation) { r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation); if (r_glsl_permutation != perm) @@ -1270,7 +1365,10 @@ void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutatio if (!r_glsl_permutation->program) { if (!r_glsl_permutation->compiled) + { + Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation); R_GLSL_CompilePermutation(perm, mode, permutation); + } if (!r_glsl_permutation->program) { // remove features until we find a valid permutation @@ -1290,7 +1388,7 @@ void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutatio } if (i >= SHADERPERMUTATION_COUNT) { - //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext); + //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext); r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation); qglUseProgram(0);CHECKGLERROR return; // no bit left to clear, entire mode is broken @@ -1303,6 +1401,7 @@ void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutatio if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f); if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f); if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time); + CHECKGLERROR } #ifdef SUPPORTD3D @@ -1431,35 +1530,6 @@ static r_hlsl_permutation_t *R_HLSL_FindPermutation(unsigned int mode, unsigned return p; } -static char *R_HLSL_GetText(const char *filename, qboolean printfromdisknotice) -{ - char *shaderstring; - if (!filename || !filename[0]) - return NULL; - if (!strcmp(filename, "hlsl/default.hlsl")) - { - if (!hlslshaderstring) - { - hlslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); - if (hlslshaderstring) - Con_DPrintf("Loading shaders from file %s...\n", filename); - else - hlslshaderstring = (char *)builtinhlslshaderstring; - } - shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(hlslshaderstring) + 1); - memcpy(shaderstring, hlslshaderstring, strlen(hlslshaderstring) + 1); - return shaderstring; - } - shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); - if (shaderstring) - { - if (printfromdisknotice) - Con_DPrintf("from disk %s... ", filename); - return shaderstring; - } - return shaderstring; -} - #include //#include //#include @@ -1482,13 +1552,14 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c int psresult = 0; char temp[MAX_INPUTLINE]; const char *vsversion = "vs_3_0", *psversion = "ps_3_0"; + char vabuf[1024]; qboolean debugshader = gl_paranoid.integer != 0; if (p->permutation & SHADERPERMUTATION_OFFSETMAPPING) {vsversion = "vs_3_0";psversion = "ps_3_0";} if (p->permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) {vsversion = "vs_3_0";psversion = "ps_3_0";} if (!debugshader) { - vsbin = (DWORD *)FS_LoadFile(va("%s.vsbin", cachename), r_main_mempool, true, &vsbinsize); - psbin = (DWORD *)FS_LoadFile(va("%s.psbin", cachename), r_main_mempool, true, &psbinsize); + vsbin = (DWORD *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.vsbin", cachename), r_main_mempool, true, &vsbinsize); + psbin = (DWORD *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.psbin", cachename), r_main_mempool, true, &psbinsize); } if ((!vsbin && vertstring) || (!psbin && fragstring)) { @@ -1527,6 +1598,18 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c {"D3DXCompileShader", (void **) &qD3DXCompileShader}, {NULL, NULL} }; + // LordHavoc: the June 2010 SDK lacks these macros to make ID3DXBuffer usable in C, and to make it work in both C and C++ the macros are needed... +#ifndef ID3DXBuffer_GetBufferPointer +#if !defined(__cplusplus) || defined(CINTERFACE) +#define ID3DXBuffer_GetBufferPointer(p) (p)->lpVtbl->GetBufferPointer(p) +#define ID3DXBuffer_GetBufferSize(p) (p)->lpVtbl->GetBufferSize(p) +#define ID3DXBuffer_Release(p) (p)->lpVtbl->Release(p) +#else +#define ID3DXBuffer_GetBufferPointer(p) (p)->GetBufferPointer() +#define ID3DXBuffer_GetBufferSize(p) (p)->GetBufferSize() +#define ID3DXBuffer_Release(p) (p)->Release() +#endif +#endif if (Sys_LoadLibrary(dllnames_d3dx9, &d3dx9_dll, d3dx9_dllfuncs)) { DWORD shaderflags = 0; @@ -1538,50 +1621,46 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c { if (debugshader) { -// vsresult = qD3DXPreprocessShader(vertstring, strlen(vertstring), NULL, NULL, &vsbuffer, &vslog); -// FS_WriteFile(va("%s_vs.fx", cachename), vsbuffer->GetBufferPointer(), vsbuffer->GetBufferSize()); - FS_WriteFile(va("%s_vs.fx", cachename), vertstring, strlen(vertstring)); - vsresult = qD3DXCompileShaderFromFileA(va("%s/%s_vs.fx", fs_gamedir, cachename), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable); + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_vs.fx", cachename), vertstring, strlen(vertstring)); + vsresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_vs.fx", fs_gamedir, cachename), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable); } else vsresult = qD3DXCompileShader(vertstring, strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable); if (vsbuffer) { - vsbinsize = vsbuffer->GetBufferSize(); + vsbinsize = ID3DXBuffer_GetBufferSize(vsbuffer); vsbin = (DWORD *)Mem_Alloc(tempmempool, vsbinsize); - memcpy(vsbin, vsbuffer->GetBufferPointer(), vsbinsize); - vsbuffer->Release(); + memcpy(vsbin, ID3DXBuffer_GetBufferPointer(vsbuffer), vsbinsize); + ID3DXBuffer_Release(vsbuffer); } if (vslog) { - strlcpy(temp, (const char *)vslog->GetBufferPointer(), min(sizeof(temp), vslog->GetBufferSize())); + strlcpy(temp, (const char *)ID3DXBuffer_GetBufferPointer(vslog), min(sizeof(temp), ID3DXBuffer_GetBufferSize(vslog))); Con_DPrintf("HLSL vertex shader compile output for %s follows:\n%s\n", cachename, temp); - vslog->Release(); + ID3DXBuffer_Release(vslog); } } if (fragstring && fragstring[0]) { if (debugshader) { -// psresult = qD3DXPreprocessShader(fragstring, strlen(fragstring), NULL, NULL, &psbuffer, &pslog); -// FS_WriteFile(va("%s_ps.fx", cachename), psbuffer->GetBufferPointer(), psbuffer->GetBufferSize()); - FS_WriteFile(va("%s_ps.fx", cachename), fragstring, strlen(fragstring)); - psresult = qD3DXCompileShaderFromFileA(va("%s/%s_ps.fx", fs_gamedir, cachename), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable); + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_ps.fx", cachename), fragstring, strlen(fragstring)); + psresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_ps.fx", fs_gamedir, cachename), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable); } else psresult = qD3DXCompileShader(fragstring, strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable); if (psbuffer) { - psbinsize = psbuffer->GetBufferSize(); + psbinsize = ID3DXBuffer_GetBufferSize(psbuffer); psbin = (DWORD *)Mem_Alloc(tempmempool, psbinsize); - memcpy(psbin, psbuffer->GetBufferPointer(), psbinsize); - psbuffer->Release(); + memcpy(psbin, ID3DXBuffer_GetBufferPointer(psbuffer), psbinsize); + ID3DXBuffer_Release(psbuffer); } if (pslog) { - strlcpy(temp, (const char *)pslog->GetBufferPointer(), min(sizeof(temp), pslog->GetBufferSize())); + strlcpy(temp, (const char *)ID3DXBuffer_GetBufferPointer(pslog), min(sizeof(temp), ID3DXBuffer_GetBufferSize(pslog))); Con_DPrintf("HLSL pixel shader compile output for %s follows:\n%s\n", cachename, temp); - pslog->Release(); + ID3DXBuffer_Release(pslog); } } Sys_UnloadLibrary(&d3dx9_dll); @@ -1611,16 +1690,16 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode int geomstring_length = 0; int fragstring_length = 0; char *t; - char *vertexstring, *geometrystring, *fragmentstring; + char *sourcestring; char *vertstring, *geomstring, *fragstring; char permutationname[256]; char cachename[256]; int vertstrings_count = 0; int geomstrings_count = 0; int fragstrings_count = 0; - const char *vertstrings_list[32+3+SHADERSTATICPARMS_COUNT+1]; - const char *geomstrings_list[32+3+SHADERSTATICPARMS_COUNT+1]; - const char *fragstrings_list[32+3+SHADERSTATICPARMS_COUNT+1]; + const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; if (p->compiled) return; @@ -1630,11 +1709,9 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode permutationname[0] = 0; cachename[0] = 0; - vertexstring = R_HLSL_GetText(modeinfo->vertexfilename, true); - geometrystring = R_HLSL_GetText(modeinfo->geometryfilename, false); - fragmentstring = R_HLSL_GetText(modeinfo->fragmentfilename, false); + sourcestring = R_GetShaderText(modeinfo->filename, true, false); - strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname)); + strlcat(permutationname, modeinfo->filename, sizeof(permutationname)); strlcat(cachename, "hlsl/", sizeof(cachename)); // define HLSL so that the shader can tell apart the HLSL compiler and the Cg compiler @@ -1693,17 +1770,9 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode cachename[i] = '_'; // now append the shader text itself - vertstrings_list[vertstrings_count++] = vertexstring; - geomstrings_list[geomstrings_count++] = geometrystring; - fragstrings_list[fragstrings_count++] = fragmentstring; - - // if any sources were NULL, clear the respective list - if (!vertexstring) - vertstrings_count = 0; - if (!geometrystring) - geomstrings_count = 0; - if (!fragmentstring) - fragstrings_count = 0; + vertstrings_list[vertstrings_count++] = sourcestring; + geomstrings_list[geomstrings_count++] = sourcestring; + fragstrings_list[fragstrings_count++] = sourcestring; vertstring_length = 0; for (i = 0;i < vertstrings_count;i++) @@ -1741,12 +1810,8 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode Mem_Free(geomstring); if (fragstring) Mem_Free(fragstring); - if (vertexstring) - Mem_Free(vertexstring); - if (geometrystring) - Mem_Free(geometrystring); - if (fragmentstring) - Mem_Free(fragmentstring); + if (sourcestring) + Mem_Free(sourcestring); } static inline void hlslVSSetParameter16f(D3DVSREGISTER_t r, const float *a) {IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, a, 4);} @@ -1792,7 +1857,7 @@ void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutatio } if (i >= SHADERPERMUTATION_COUNT) { - //Con_Printf("Could not find a working HLSL shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext); + //Con_Printf("Could not find a working HLSL shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext); r_hlsl_permutation = R_HLSL_FindPermutation(mode, permutation); return; // no bit left to clear, entire mode is broken } @@ -1807,7 +1872,7 @@ void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutatio } #endif -void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int permutation) +static void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int permutation) { DPSOFTRAST_SetShader(mode, permutation, r_shadow_glossexact.integer); DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f); @@ -1818,10 +1883,10 @@ void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int permutatio void R_GLSL_Restart_f(void) { unsigned int i, limit; - if (glslshaderstring && glslshaderstring != builtinshaderstring) + if (glslshaderstring) Mem_Free(glslshaderstring); glslshaderstring = NULL; - if (hlslshaderstring && hlslshaderstring != builtinhlslshaderstring) + if (hlslshaderstring) Mem_Free(hlslshaderstring); hlslshaderstring = NULL; switch(vid.renderpath) @@ -1879,47 +1944,49 @@ void R_GLSL_Restart_f(void) } } -void R_GLSL_DumpShader_f(void) +static void R_GLSL_DumpShader_f(void) { - int i; + int i, language, mode, dupe; + char *text; + shadermodeinfo_t *modeinfo; qfile_t *file; - file = FS_OpenRealFile("glsl/default.glsl", "w", false); - if (file) + for (language = 0;language < 2;language++) { - FS_Print(file, "/* The engine may define the following macros:\n"); - FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n"); - for (i = 0;i < SHADERMODE_COUNT;i++) - FS_Print(file, glslshadermodeinfo[i].pretext); - for (i = 0;i < SHADERPERMUTATION_COUNT;i++) - FS_Print(file, shaderpermutationinfo[i].pretext); - FS_Print(file, "*/\n"); - FS_Print(file, builtinshaderstring); - FS_Close(file); - Con_Printf("glsl/default.glsl written\n"); - } - else - Con_Printf("failed to write to glsl/default.glsl\n"); - - file = FS_OpenRealFile("hlsl/default.hlsl", "w", false); - if (file) - { - FS_Print(file, "/* The engine may define the following macros:\n"); - FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n"); - for (i = 0;i < SHADERMODE_COUNT;i++) - FS_Print(file, hlslshadermodeinfo[i].pretext); - for (i = 0;i < SHADERPERMUTATION_COUNT;i++) - FS_Print(file, shaderpermutationinfo[i].pretext); - FS_Print(file, "*/\n"); - FS_Print(file, builtinhlslshaderstring); - FS_Close(file); - Con_Printf("hlsl/default.hlsl written\n"); + modeinfo = (language == 0 ? glslshadermodeinfo : hlslshadermodeinfo); + for (mode = 0;mode < SHADERMODE_COUNT;mode++) + { + // don't dump the same file multiple times (most or all shaders come from the same file) + for (dupe = mode - 1;dupe >= 0;dupe--) + if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename)) + break; + if (dupe >= 0) + continue; + text = R_GetShaderText(modeinfo[mode].filename, false, true); + if (!text) + continue; + file = FS_OpenRealFile(modeinfo[mode].filename, "w", false); + if (file) + { + FS_Print(file, "/* The engine may define the following macros:\n"); + FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n"); + for (i = 0;i < SHADERMODE_COUNT;i++) + FS_Print(file, modeinfo[i].pretext); + for (i = 0;i < SHADERPERMUTATION_COUNT;i++) + FS_Print(file, shaderpermutationinfo[i].pretext); + FS_Print(file, "*/\n"); + FS_Print(file, text); + FS_Close(file); + Con_Printf("%s written\n", modeinfo[mode].filename); + } + else + Con_Printf("failed to write to %s\n", modeinfo[mode].filename); + Mem_Free(text); + } } - else - Con_Printf("failed to write to hlsl/default.hlsl\n"); } -void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy) +void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha) { unsigned int permutation = 0; if (r_trippy.integer && !notrippy) @@ -1937,6 +2004,8 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; if (usegamma && v_glslgamma.integer && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial) permutation |= SHADERPERMUTATION_GAMMARAMPS; + if (suppresstexalpha) + permutation |= SHADERPERMUTATION_REFLECTCUBE; if (!second) texturemode = GL_MODULATE; if (vid.allowalphatocoverage) @@ -1961,8 +2030,10 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod case RENDERPATH_GL20: case RENDERPATH_GLES2: R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation); - R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first ); - R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second); + if (r_glsl_permutation->tex_Texture_First >= 0) + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first ); + if (r_glsl_permutation->tex_Texture_Second >= 0) + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second); if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps); break; @@ -1970,12 +2041,18 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod case RENDERPATH_GLES1: R_Mesh_TexBind(0, first ); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexMatrix(0, NULL); R_Mesh_TexBind(1, second); if (second) + { R_Mesh_TexCombine(1, texturemode, texturemode, rgbscale, 1); + R_Mesh_TexMatrix(1, NULL); + } break; case RENDERPATH_GL11: R_Mesh_TexBind(0, first ); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexMatrix(0, NULL); break; case RENDERPATH_SOFT: R_SetupShader_SetPermutationSoft(SHADERMODE_GENERIC, permutation); @@ -1985,11 +2062,21 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod } } -void R_SetupShader_DepthOrShadow(qboolean notrippy) +void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy) +{ + R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false); +} + +void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal) { unsigned int permutation = 0; if (r_trippy.integer && !notrippy) permutation |= SHADERPERMUTATION_TRIPPY; + if (depthrgb) + permutation |= SHADERPERMUTATION_DEPTHRGB; + if (skeletal) + permutation |= SHADERPERMUTATION_SKELETAL; + if (vid.allowalphatocoverage) GL_AlphaToCoverage(false); switch (vid.renderpath) @@ -2008,6 +2095,9 @@ void R_SetupShader_DepthOrShadow(qboolean notrippy) case RENDERPATH_GL20: case RENDERPATH_GLES2: R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation); +#ifndef USE_GLES2 /* FIXME: GLES3 only */ + 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); +#endif break; case RENDERPATH_GL13: case RENDERPATH_GLES1: @@ -2023,43 +2113,7 @@ void R_SetupShader_DepthOrShadow(qboolean notrippy) } } -void R_SetupShader_ShowDepth(qboolean notrippy) -{ - int permutation = 0; - if (r_trippy.integer && !notrippy) - permutation |= SHADERPERMUTATION_TRIPPY; - if (vid.allowalphatocoverage) - GL_AlphaToCoverage(false); - switch (vid.renderpath) - { - case RENDERPATH_D3D9: -#ifdef SUPPORTHLSL - R_SetupShader_SetPermutationHLSL(SHADERMODE_SHOWDEPTH, permutation); -#endif - break; - case RENDERPATH_D3D10: - Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); - break; - case RENDERPATH_D3D11: - Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); - break; - case RENDERPATH_GL20: - case RENDERPATH_GLES2: - R_SetupShader_SetPermutationGLSL(SHADERMODE_SHOWDEPTH, permutation); - break; - case RENDERPATH_GL13: - case RENDERPATH_GLES1: - break; - case RENDERPATH_GL11: - break; - case RENDERPATH_SOFT: - R_SetupShader_SetPermutationSoft(SHADERMODE_SHOWDEPTH, permutation); - break; - } -} - extern qboolean r_shadow_usingdeferredprepass; -extern cvar_t r_shadow_deferred_8bitrange; extern rtexture_t *r_shadow_attenuationgradienttexture; extern rtexture_t *r_shadow_attenuation2dtexture; extern rtexture_t *r_shadow_attenuation3dtexture; @@ -2068,18 +2122,15 @@ extern qboolean r_shadow_usingshadowmaportho; extern float r_shadow_shadowmap_texturescale[2]; extern float r_shadow_shadowmap_parameters[4]; extern qboolean r_shadow_shadowmapvsdct; -extern qboolean r_shadow_shadowmapsampler; -extern int r_shadow_shadowmappcf; -extern rtexture_t *r_shadow_shadowmap2dtexture; -extern rtexture_t *r_shadow_shadowmap2dcolortexture; +extern rtexture_t *r_shadow_shadowmap2ddepthbuffer; +extern rtexture_t *r_shadow_shadowmap2ddepthtexture; extern rtexture_t *r_shadow_shadowmapvsdcttexture; extern matrix4x4_t r_shadow_shadowmapmatrix; extern int r_shadow_shadowmaplod; // changes for each light based on distance extern int r_shadow_prepass_width; extern int r_shadow_prepass_height; -extern rtexture_t *r_shadow_prepassgeometrydepthtexture; +extern rtexture_t *r_shadow_prepassgeometrydepthbuffer; extern rtexture_t *r_shadow_prepassgeometrynormalmaptexture; -extern rtexture_t *r_shadow_prepassgeometrydepthcolortexture; extern rtexture_t *r_shadow_prepasslightingdiffusetexture; extern rtexture_t *r_shadow_prepasslightingspeculartexture; @@ -2155,6 +2206,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER) { mode = SHADERMODE_WATER; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; if((r_wateralpha.value < 1) && (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA)) { // this is the right thing to do for wateralpha @@ -2171,15 +2224,17 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION) { mode = SHADERMODE_REFRACTION; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { mode = SHADERMODE_GENERIC; - permutation |= SHADERPERMUTATION_DIFFUSE; - GL_BlendFunc(GL_ONE, GL_ZERO); - blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO); + permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } if (vid.allowalphatocoverage) GL_AlphaToCoverage(false); @@ -2219,6 +2274,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // light source mode = SHADERMODE_LIGHTSOURCE; if (rsurface.rtlight->currentcubemap != r_texture_whitecube) @@ -2237,12 +2294,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if(r_shadow_shadowmapvsdct) permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; } if (rsurface.texture->reflectmasktexture) permutation |= SHADERPERMUTATION_REFLECTCUBE; @@ -2265,10 +2318,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // unshaded geometry (fullbright or ambient model lighting) mode = SHADERMODE_FLATCOLOR; ambientscale = diffusescale = specularscale = 0; - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; if (r_refdef.fogenabled) permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); @@ -2279,12 +2334,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) permutation |= SHADERPERMUTATION_REFLECTION; @@ -2318,9 +2369,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // directional model lighting mode = SHADERMODE_LIGHTDIRECTION; - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; permutation |= SHADERPERMUTATION_DIFFUSE; if (specularscale > 0) @@ -2334,12 +2387,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) permutation |= SHADERPERMUTATION_REFLECTION; @@ -2381,9 +2430,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // ambient model lighting mode = SHADERMODE_LIGHTDIRECTION; - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; if (r_refdef.fogenabled) permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); @@ -2394,12 +2445,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) permutation |= SHADERPERMUTATION_REFLECTION; @@ -2441,8 +2488,10 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // lightmapped wall - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; if (r_refdef.fogenabled) permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); @@ -2453,12 +2502,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) permutation |= SHADERPERMUTATION_REFLECTION; @@ -2536,8 +2581,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, { case RENDERPATH_D3D9: #ifdef SUPPORTD3D - RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist); - R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer); + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset); R_SetupShader_SetPermutationHLSL(mode, permutation); Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);hlslPSSetParameter16f(D3DPSREGISTER_ModelToReflectCube, m16f); if (mode == SHADERMODE_LIGHTSOURCE) @@ -2581,8 +2626,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity) * colormod[2]); hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]); hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); - hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0] * r_shadow_deferred_8bitrange.value, colormod[1] * r_shadow_deferred_8bitrange.value, colormod[2] * r_shadow_deferred_8bitrange.value); - hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale, specularscale, specularscale); hlslPSSetParameter3f(D3DPSREGISTER_LightColor, rsurface.modellight_diffuse[0], rsurface.modellight_diffuse[1], rsurface.modellight_diffuse[2]); hlslPSSetParameter3f(D3DPSREGISTER_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]); } @@ -2591,8 +2636,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]); hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]); hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); - hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value); - hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale, specularscale, specularscale); } // additive passes are only darkened by fog, not tinted if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0) @@ -2600,8 +2645,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, else hlslPSSetParameter3f(D3DPSREGISTER_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]); hlslPSSetParameter4f(D3DPSREGISTER_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor); - hlslPSSetParameter4f(D3DPSREGISTER_ScreenScaleRefractReflect, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]); - hlslPSSetParameter4f(D3DPSREGISTER_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]); + hlslPSSetParameter4f(D3DPSREGISTER_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]); + hlslPSSetParameter4f(D3DPSREGISTER_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]); hlslPSSetParameter4f(D3DPSREGISTER_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]); hlslPSSetParameter4f(D3DPSREGISTER_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]); hlslPSSetParameter1f(D3DPSREGISTER_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin); @@ -2613,7 +2658,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); hlslPSSetParameter3f(D3DPSREGISTER_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]); - hlslPSSetParameter1f(D3DPSREGISTER_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); + hlslPSSetParameter1f(D3DPSREGISTER_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); hlslPSSetParameter3f(D3DPSREGISTER_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]); if (rsurface.texture->pantstexture) hlslPSSetParameter3f(D3DPSREGISTER_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]); @@ -2633,7 +2678,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); - hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer); + hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_Bias, rsurface.texture->offsetbias); hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height); @@ -2665,13 +2710,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, { if (permutation & SHADERPERMUTATION_REFLECTION ) R_Mesh_TexBind(GL20TU_REFLECTION , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); } -// if (rsurfacepass == RSURFPASS_DEFERREDLIGHT ) R_Mesh_TexBind(GL20TU_SCREENDEPTH , r_shadow_prepassgeometrydepthtexture ); // if (rsurfacepass == RSURFPASS_DEFERREDLIGHT ) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE , r_shadow_prepasslightingdiffusetexture ); if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENSPECULAR , r_shadow_prepasslightingspeculartexture ); if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))) { - R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2dcolortexture); + R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2ddepthtexture); if (rsurface.rtlight) { if (permutation & SHADERPERMUTATION_CUBEFILTER ) R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); @@ -2690,7 +2734,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, case RENDERPATH_GLES2: if (!vid.useinterleavedarrays) { - 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), texturenumsurfaces, texturesurfacelist); + 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); R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset); R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); @@ -2698,13 +2742,22 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset); R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset); R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset); } else { - RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist); - R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer); + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset); } + // this has to be after RSurf_PrepareVerticesForBatch + if (rsurface.batchskeletaltransform3x4buffer) + permutation |= SHADERPERMUTATION_SKELETAL; R_SetupShader_SetPermutationGLSL(mode, permutation); +#ifndef USE_GLES2 /* FIXME: GLES3 only */ + 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); +#endif if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);} if (mode == SHADERMODE_LIGHTSOURCE) { @@ -2731,8 +2784,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[2]); if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]); if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); - if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0] * r_shadow_deferred_8bitrange.value, colormod[1] * r_shadow_deferred_8bitrange.value, colormod[2] * r_shadow_deferred_8bitrange.value); - if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value); + if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]); + if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale, specularscale, specularscale); if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, rsurface.modellight_diffuse[0] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[1] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[2] * r_refdef.scene.rtlightstylevalue[0]); if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]); } @@ -2741,8 +2794,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]); if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]); if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); - if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value); - if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value); + if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale, specularscale, specularscale); } // additive passes are only darkened by fog, not tinted if (r_glsl_permutation->loc_FogColor >= 0) @@ -2753,8 +2806,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]); } if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor); - if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]); - if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]); + 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]); + 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]); if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]); if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]); if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin); @@ -2769,7 +2822,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]); - if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); + if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]); if (r_glsl_permutation->loc_Color_Pants >= 0) { @@ -2795,7 +2848,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); - if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer); + 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); if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, rsurface.texture->offsetbias); 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]); if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); @@ -2832,13 +2885,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, { if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); } - if (r_glsl_permutation->tex_Texture_ScreenDepth >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDepth , r_shadow_prepassgeometrydepthtexture ); if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture ); if (r_glsl_permutation->tex_Texture_ScreenDiffuse >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse , r_shadow_prepasslightingdiffusetexture ); if (r_glsl_permutation->tex_Texture_ScreenSpecular >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture ); if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))) { - if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2dtexture ); + if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture ); if (rsurface.rtlight) { if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap ); @@ -2853,7 +2905,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, case RENDERPATH_GLES1: break; case RENDERPATH_SOFT: - 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), texturenumsurfaces, texturesurfacelist); + 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); R_Mesh_PrepareVertices_Mesh_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchsvector3f, rsurface.batchtvector3f, rsurface.batchnormal3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f); R_SetupShader_SetPermutationSoft(mode, permutation); {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelToReflectCubeM1, 1, false, m16f);} @@ -2881,8 +2933,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[2]); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); - DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0] * r_shadow_deferred_8bitrange.value, colormod[1] * r_shadow_deferred_8bitrange.value, colormod[2] * r_shadow_deferred_8bitrange.value); - DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale, specularscale, specularscale); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightColor, rsurface.modellight_diffuse[0] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[1] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[2] * r_refdef.scene.rtlightstylevalue[0]); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]); } @@ -2891,8 +2943,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); - DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value); - DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale, specularscale, specularscale); } // additive passes are only darkened by fog, not tinted if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0) @@ -2900,8 +2952,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, else DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]); DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor); - DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]); - DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]); DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]); DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]); DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin); @@ -2916,7 +2968,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]); - DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]); if (DPSOFTRAST_UNIFORM_Color_Pants >= 0) { @@ -2942,7 +2994,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); - DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_Bias, rsurface.texture->offsetbias); DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); @@ -2974,13 +3026,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, { if (permutation & SHADERPERMUTATION_REFLECTION ) R_Mesh_TexBind(GL20TU_REFLECTION , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); } -// if (rsurfacepass == RSURFPASS_DEFERREDLIGHT ) R_Mesh_TexBind(GL20TU_SCREENDEPTH , r_shadow_prepassgeometrydepthtexture ); // if (rsurfacepass == RSURFPASS_DEFERREDLIGHT ) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE , r_shadow_prepasslightingdiffusetexture ); if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENSPECULAR , r_shadow_prepasslightingspeculartexture ); if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))) { - R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2dcolortexture); + R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2ddepthtexture); if (rsurface.rtlight) { if (permutation & SHADERPERMUTATION_CUBEFILTER ) R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); @@ -3009,7 +3060,6 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) matrix4x4_t viewtolight; matrix4x4_t lighttoview; float viewtolight16f[16]; - float range = 1.0f / r_shadow_deferred_8bitrange.value; // light source mode = SHADERMODE_DEFERREDLIGHTSOURCE; if (rtlight->currentcubemap != r_texture_whitecube) @@ -3024,12 +3074,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) if (r_shadow_shadowmapvsdct) permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; } if (vid.allowalphatocoverage) GL_AlphaToCoverage(false); @@ -3044,9 +3090,9 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) R_SetupShader_SetPermutationHLSL(mode, permutation); hlslPSSetParameter3f(D3DPSREGISTER_LightPosition, viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]); hlslPSSetParameter16f(D3DPSREGISTER_ViewToLight, viewtolight16f); - hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Ambient , lightcolorbase[0] * ambientscale * range, lightcolorbase[1] * ambientscale * range, lightcolorbase[2] * ambientscale * range); - hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale * range, lightcolorbase[1] * diffusescale * range, lightcolorbase[2] * diffusescale * range); - hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale ); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale ); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale); hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); @@ -3054,10 +3100,9 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height); R_Mesh_TexBind(GL20TU_ATTENUATION , r_shadow_attenuationgradienttexture ); - R_Mesh_TexBind(GL20TU_SCREENDEPTH , r_shadow_prepassgeometrydepthcolortexture ); R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); - R_Mesh_TexBind(GL20TU_SHADOWMAP2D , r_shadow_shadowmap2dcolortexture ); + R_Mesh_TexBind(GL20TU_SHADOWMAP2D , r_shadow_shadowmap2ddepthtexture ); R_Mesh_TexBind(GL20TU_CUBEPROJECTION , r_shadow_shadowmapvsdcttexture ); #endif break; @@ -3072,9 +3117,9 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) R_SetupShader_SetPermutationGLSL(mode, permutation); if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f( r_glsl_permutation->loc_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]); if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight , 1, false, viewtolight16f); - if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale * range, lightcolorbase[1] * ambientscale * range, lightcolorbase[2] * ambientscale * range); - if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale * range, lightcolorbase[1] * diffusescale * range, lightcolorbase[2] * diffusescale * range); - if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range); + if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale ); + if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale ); + if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale); if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2f( r_glsl_permutation->loc_ShadowMap_TextureScale , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f( r_glsl_permutation->loc_ShadowMap_Parameters , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); 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); @@ -3082,10 +3127,9 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/vid.width, 1.0f/vid.height); if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture ); - if (r_glsl_permutation->tex_Texture_ScreenDepth >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDepth , r_shadow_prepassgeometrydepthtexture ); if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture ); if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap ); - if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2dtexture ); + if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2ddepthtexture ); if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture ); break; case RENDERPATH_GL11: @@ -3096,9 +3140,9 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) R_SetupShader_SetPermutationGLSL(mode, permutation); DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]); DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ViewToLightM1 , 1, false, viewtolight16f); - DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Ambient , lightcolorbase[0] * ambientscale * range, lightcolorbase[1] * ambientscale * range, lightcolorbase[2] * ambientscale * range); - DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale * range, lightcolorbase[1] * diffusescale * range, lightcolorbase[2] * diffusescale * range); - DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Specular , lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range); + DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale ); + DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale ); + DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale); DPSOFTRAST_Uniform2f( DPSOFTRAST_UNIFORM_ShadowMap_TextureScale , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); DPSOFTRAST_Uniform4f( DPSOFTRAST_UNIFORM_ShadowMap_Parameters , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); DPSOFTRAST_Uniform1f( DPSOFTRAST_UNIFORM_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); @@ -3106,10 +3150,9 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); R_Mesh_TexBind(GL20TU_ATTENUATION , r_shadow_attenuationgradienttexture ); - R_Mesh_TexBind(GL20TU_SCREENDEPTH , r_shadow_prepassgeometrydepthtexture ); R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); - R_Mesh_TexBind(GL20TU_SHADOWMAP2D , r_shadow_shadowmap2dtexture ); + R_Mesh_TexBind(GL20TU_SHADOWMAP2D , r_shadow_shadowmap2ddepthtexture ); R_Mesh_TexBind(GL20TU_CUBEPROJECTION , r_shadow_shadowmapvsdcttexture ); break; } @@ -3311,6 +3354,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole int miplevel = R_PicmipForFlags(textureflags); int savemiplevel = miplevel; int mymiplevel; + char vabuf[1024]; if (cls.state == ca_dedicated) return NULL; @@ -3325,7 +3369,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole Image_StripImageExtension(name, basename, sizeof(basename)); // check for DDS texture file first - if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s.dds", basename), textureflags, &ddshasalpha, ddsavgcolor, miplevel))) + if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false))) { basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel); if (basepixels == NULL) @@ -3359,7 +3403,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole skinframe->hasalpha = ddshasalpha; VectorCopy(ddsavgcolor, skinframe->avgcolor); if (r_loadfog && skinframe->hasalpha) - skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_mask.dds", skinframe->basename), textureflags | TEXF_ALPHA, NULL, NULL, miplevel); + 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); //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]); } else @@ -3388,7 +3432,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole pixels[j+2] = 255; pixels[j+3] = basepixels[j+3]; } - skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL); + 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); Mem_Free(pixels); } } @@ -3396,9 +3440,9 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole #ifndef USE_GLES2 //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]); if (r_savedds && qglGetCompressedTexImageARB && skinframe->base) - R_SaveTextureDDSFile(skinframe->base, va("dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha); + R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha); if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog) - R_SaveTextureDDSFile(skinframe->fog, va("dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); + R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); #endif } @@ -3406,30 +3450,30 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole { mymiplevel = savemiplevel; if (r_loadnormalmap) - skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_norm.dds", skinframe->basename), (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel); - skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_glow.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel); + 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); + skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); if (r_loadgloss) - skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_gloss.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel); - skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_pants.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel); - skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_shirt.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel); - skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_reflect.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel); + skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); } // _norm is the name used by tenebrae and has been adopted as standard if (r_loadnormalmap && skinframe->nmap == NULL) { mymiplevel = savemiplevel; - if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL) + if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL) { - skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); Mem_Free(pixels); pixels = NULL; } - else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL) + else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL) { pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value); - skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); Mem_Free(pixels); Mem_Free(bumppixels); } @@ -3437,71 +3481,71 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole { pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4); Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value); - skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); Mem_Free(pixels); } #ifndef USE_GLES2 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap) - R_SaveTextureDDSFile(skinframe->nmap, va("dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); + R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); #endif } // _luma is supported only for tenebrae compatibility // _glow is the preferred name mymiplevel = savemiplevel; - if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false, false, &mymiplevel)))) + if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel)))) { - skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); #ifndef USE_GLES2 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow) - R_SaveTextureDDSFile(skinframe->glow, va("dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); + R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); #endif Mem_Free(pixels);pixels = NULL; } mymiplevel = savemiplevel; - if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false, false, &mymiplevel))) + if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); #ifndef USE_GLES2 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss) - R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); + R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); #endif Mem_Free(pixels); pixels = NULL; } mymiplevel = savemiplevel; - if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false, false, &mymiplevel))) + if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); #ifndef USE_GLES2 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants) - R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false); + R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false); #endif Mem_Free(pixels); pixels = NULL; } mymiplevel = savemiplevel; - if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false, false, &mymiplevel))) + if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); #ifndef USE_GLES2 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt) - R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false); + R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false); #endif Mem_Free(pixels); pixels = NULL; } mymiplevel = savemiplevel; - if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%s_reflect", skinframe->basename), false, false, false, &mymiplevel))) + if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va("%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); + 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); #ifndef USE_GLES2 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect) - R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); + R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); #endif Mem_Free(pixels); pixels = NULL; @@ -3519,13 +3563,14 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co int i; unsigned char *temp1, *temp2; skinframe_t *skinframe; + char vabuf[1024]; if (cls.state == ca_dedicated) return NULL; // if already loaded just return it, otherwise make a new skinframe skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : skindata ? CRC_Block(skindata, width*height*4) : 0, true); - if (skinframe && skinframe->base) + if (skinframe->base) return skinframe; textureflags &= ~TEXF_FORCE_RELOAD; @@ -3553,7 +3598,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8); temp2 = temp1 + width * height * 4; Image_HeightmapToNormalmap_BGRA(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value); - skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL); + skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL); Mem_Free(temp1); } skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL); @@ -3573,7 +3618,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co memcpy(fogpixels, skindata, width * height * 4); for (i = 0;i < width * height * 4;i += 4) fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255; - skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL); + skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL); Mem_Free(fogpixels); } } @@ -3595,9 +3640,9 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i // if already loaded just return it, otherwise make a new skinframe skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true); - if (skinframe && skinframe->base) + if (skinframe->base) return skinframe; - textureflags &= ~TEXF_FORCE_RELOAD; + //textureflags &= ~TEXF_FORCE_RELOAD; skinframe->stain = NULL; skinframe->merged = NULL; @@ -3646,6 +3691,7 @@ static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboo int width; int height; unsigned char *skindata; + char vabuf[1024]; if (!skinframe->qpixels) return; @@ -3677,22 +3723,22 @@ static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboo // use either a custom palette or the quake palette Image_Copy8bitBGRA(skindata, temp1, width * height, palette_bgra_complete); Image_HeightmapToNormalmap_BGRA(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value); - skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL); + skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL); Mem_Free(temp1); } if (skinframe->qgenerateglow) { skinframe->qgenerateglow = false; - skinframe->glow = R_LoadTexture2D(r_main_texturepool, va("%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow + 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 } if (colormapped) { skinframe->qgeneratebase = false; - skinframe->base = R_LoadTexture2D(r_main_texturepool, va("%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); - skinframe->pants = R_LoadTexture2D(r_main_texturepool, va("%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite); - skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va("%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite); + 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); + 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); + 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); } else { @@ -3711,13 +3757,14 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co { int i; skinframe_t *skinframe; + char vabuf[1024]; if (cls.state == ca_dedicated) return NULL; // if already loaded just return it, otherwise make a new skinframe skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true); - if (skinframe && skinframe->base) + if (skinframe->base) return skinframe; textureflags &= ~TEXF_FORCE_RELOAD; @@ -3752,7 +3799,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co } } if (r_loadfog && skinframe->hasalpha) - skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette); + skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette); } R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]); @@ -3826,7 +3873,7 @@ static suffixinfo_t suffix[3][6] = static int componentorder[4] = {0, 1, 2, 3}; -rtexture_t *R_LoadCubemap(const char *basename) +static rtexture_t *R_LoadCubemap(const char *basename) { int i, j, cubemapsize; unsigned char *cubemappixels, *image_buffer; @@ -3908,44 +3955,7 @@ rtexture_t *R_GetCubemap(const char *basename) return r_texture_cubemaps[i]->texture; } -void R_FreeCubemap(const char *basename) -{ - int i; - - for (i = 0;i < r_texture_numcubemaps;i++) - { - if (r_texture_cubemaps[i] != NULL) - { - if (r_texture_cubemaps[i]->texture) - { - if (developer_loading.integer) - Con_DPrintf("unloading cubemap \"%s\"\n", r_texture_cubemaps[i]->basename); - R_FreeTexture(r_texture_cubemaps[i]->texture); - Mem_Free(r_texture_cubemaps[i]); - r_texture_cubemaps[i] = NULL; - } - } - } -} - -void R_FreeCubemaps(void) -{ - int i; - for (i = 0;i < r_texture_numcubemaps;i++) - { - if (developer_loading.integer) - Con_DPrintf("unloading cubemap \"%s\"\n", r_texture_cubemaps[i]->basename); - if (r_texture_cubemaps[i] != NULL) - { - if (r_texture_cubemaps[i]->texture) - R_FreeTexture(r_texture_cubemaps[i]->texture); - Mem_Free(r_texture_cubemaps[i]); - } - } - r_texture_numcubemaps = 0; -} - -void R_Main_FreeViewCache(void) +static void R_Main_FreeViewCache(void) { if (r_refdef.viewcache.entityvisible) Mem_Free(r_refdef.viewcache.entityvisible); @@ -3958,7 +3968,7 @@ void R_Main_FreeViewCache(void) memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache)); } -void R_Main_ResizeViewCache(void) +static void R_Main_ResizeViewCache(void) { int numentities = r_refdef.scene.numentities; int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1; @@ -3997,7 +4007,7 @@ void R_Main_ResizeViewCache(void) } extern rtexture_t *loadingscreentexture; -void gl_main_start(void) +static void gl_main_start(void) { loadingscreentexture = NULL; r_texture_blanknormalmap = NULL; @@ -4010,6 +4020,7 @@ void gl_main_start(void) r_texture_fogheighttexture = NULL; r_texture_gammaramps = NULL; r_texture_numcubemaps = 0; + r_uniformbufferalignment = 32; r_loaddds = r_texture_dds_load.integer != 0; r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer; @@ -4028,7 +4039,11 @@ void gl_main_start(void) r_loadnormalmap = true; r_loadgloss = true; r_loadfog = false; - break; +#ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT + if (vid.support.arb_uniform_buffer_object) + qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment); +#endif + break; case RENDERPATH_GL13: case RENDERPATH_GLES1: Cvar_SetValueQuick(&r_textureunits, vid.texunits); @@ -4050,6 +4065,7 @@ void gl_main_start(void) R_AnimCache_Free(); R_FrameData_Reset(); + R_BufferData_Reset(); r_numqueries = 0; r_maxqueries = 0; @@ -4078,8 +4094,7 @@ void gl_main_start(void) r_texture_fogheighttexture = NULL; r_texture_gammaramps = NULL; //r_texture_fogintensity = NULL; - memset(&r_bloomstate, 0, sizeof(r_bloomstate)); - memset(&r_waterstate, 0, sizeof(r_waterstate)); + memset(&r_fb, 0, sizeof(r_fb)); r_glsl_permutation = NULL; memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash)); Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256); @@ -4096,12 +4111,34 @@ void gl_main_start(void) r_texture_numcubemaps = 0; r_refdef.fogmasktable_density = 0; + +#ifdef __ANDROID__ + // For Steelstorm Android + // FIXME CACHE the program and reload + // FIXME see possible combinations for SS:BR android + Con_DPrintf("Compiling most used shaders for SS:BR android... START\n"); + R_SetupShader_SetPermutationGLSL(0, 12); + R_SetupShader_SetPermutationGLSL(0, 13); + R_SetupShader_SetPermutationGLSL(0, 8388621); + R_SetupShader_SetPermutationGLSL(3, 0); + R_SetupShader_SetPermutationGLSL(3, 2048); + R_SetupShader_SetPermutationGLSL(5, 0); + R_SetupShader_SetPermutationGLSL(5, 2); + R_SetupShader_SetPermutationGLSL(5, 2048); + R_SetupShader_SetPermutationGLSL(5, 8388608); + R_SetupShader_SetPermutationGLSL(11, 1); + R_SetupShader_SetPermutationGLSL(11, 2049); + R_SetupShader_SetPermutationGLSL(11, 8193); + R_SetupShader_SetPermutationGLSL(11, 10241); + Con_DPrintf("Compiling most used shaders for SS:BR android... END\n"); +#endif } -void gl_main_shutdown(void) +static void gl_main_shutdown(void) { R_AnimCache_Free(); R_FrameData_Reset(); + R_BufferData_Reset(); R_Main_FreeViewCache(); @@ -4112,7 +4149,7 @@ void gl_main_shutdown(void) case RENDERPATH_GL20: case RENDERPATH_GLES1: case RENDERPATH_GLES2: -#ifdef GL_SAMPLES_PASSED_ARB +#if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2) if (r_maxqueries) qglDeleteQueriesARB(r_maxqueries, r_queries); #endif @@ -4157,8 +4194,7 @@ void gl_main_shutdown(void) r_texture_gammaramps = NULL; r_texture_numcubemaps = 0; //r_texture_fogintensity = NULL; - memset(&r_bloomstate, 0, sizeof(r_bloomstate)); - memset(&r_waterstate, 0, sizeof(r_waterstate)); + memset(&r_fb, 0, sizeof(r_fb)); R_GLSL_Restart_f(); r_glsl_permutation = NULL; @@ -4173,8 +4209,7 @@ void gl_main_shutdown(void) hlslshaderstring = NULL; } -extern void CL_ParseEntityLump(char *entitystring); -void gl_main_newmap(void) +static void gl_main_newmap(void) { // FIXME: move this code to client char *entities, entname[MAX_QPATH]; @@ -4197,10 +4232,12 @@ void gl_main_newmap(void) R_Main_FreeViewCache(); R_FrameData_Reset(); + R_BufferData_Reset(); } void GL_Main_Init(void) { + int i; r_main_mempool = Mem_AllocPool("Renderer", 0, NULL); Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed"); @@ -4241,6 +4278,8 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_deformvertexes); Cvar_RegisterVariable(&r_transparent); Cvar_RegisterVariable(&r_transparent_alphatocoverage); + Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest); + Cvar_RegisterVariable(&r_transparent_useplanardistance); Cvar_RegisterVariable(&r_showoverdraw); Cvar_RegisterVariable(&r_showbboxes); Cvar_RegisterVariable(&r_showsurfaces); @@ -4279,6 +4318,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_shadows_throwdirection); Cvar_RegisterVariable(&r_shadows_focus); Cvar_RegisterVariable(&r_shadows_shadowmapscale); + Cvar_RegisterVariable(&r_shadows_shadowmapbias); Cvar_RegisterVariable(&r_q1bsp_skymasking); Cvar_RegisterVariable(&r_polygonoffset_submodel_factor); Cvar_RegisterVariable(&r_polygonoffset_submodel_offset); @@ -4295,6 +4335,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_texture_dds_save); Cvar_RegisterVariable(&r_textureunits); Cvar_RegisterVariable(&gl_combine); + Cvar_RegisterVariable(&r_usedepthtextures); Cvar_RegisterVariable(&r_viewfbo); Cvar_RegisterVariable(&r_viewscale); Cvar_RegisterVariable(&r_viewscale_fpsscaling); @@ -4322,6 +4363,8 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable); Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable); Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable); + Cvar_RegisterVariable(&r_celshading); + Cvar_RegisterVariable(&r_celoutlines); Cvar_RegisterVariable(&r_water); Cvar_RegisterVariable(&r_water_resolutionmultiplier); @@ -4331,6 +4374,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_water_scissormode); Cvar_RegisterVariable(&r_water_lowquality); Cvar_RegisterVariable(&r_water_hideplayer); + Cvar_RegisterVariable(&r_water_fbo); Cvar_RegisterVariable(&r_lerpsprites); Cvar_RegisterVariable(&r_lerpmodels); @@ -4343,10 +4387,9 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_bloom_resolution); Cvar_RegisterVariable(&r_bloom_colorexponent); Cvar_RegisterVariable(&r_bloom_colorsubtract); - Cvar_RegisterVariable(&r_hdr); + Cvar_RegisterVariable(&r_bloom_scenebrightness); Cvar_RegisterVariable(&r_hdr_scenebrightness); Cvar_RegisterVariable(&r_hdr_glowintensity); - Cvar_RegisterVariable(&r_hdr_range); Cvar_RegisterVariable(&r_hdr_irisadaptation); Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier); Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue); @@ -4359,29 +4402,29 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&developer_texturelogging); Cvar_RegisterVariable(&gl_lightmaps); Cvar_RegisterVariable(&r_test); + Cvar_RegisterVariable(&r_batch_multidraw); + Cvar_RegisterVariable(&r_batch_multidraw_mintriangles); + Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath); + Cvar_RegisterVariable(&r_glsl_skeletal); Cvar_RegisterVariable(&r_glsl_saturation); Cvar_RegisterVariable(&r_glsl_saturation_redcompensate); Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas); Cvar_RegisterVariable(&r_framedatasize); + for (i = 0;i < R_BUFFERDATA_COUNT;i++) + Cvar_RegisterVariable(&r_buffermegs[i]); + Cvar_RegisterVariable(&r_batch_dynamicbuffer); if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE) Cvar_SetValue("r_fullbrights", 0); +#ifdef DP_MOBILETOUCH + // GLES devices have terrible depth precision in general, so... + Cvar_SetValueQuick(&r_nearclip, 4); + Cvar_SetValueQuick(&r_farclip_base, 4096); + Cvar_SetValueQuick(&r_farclip_world, 0); + Cvar_SetValueQuick(&r_useinfinitefarclip, 0); +#endif R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL); } -extern void R_Textures_Init(void); -extern void GL_Draw_Init(void); -extern void GL_Main_Init(void); -extern void R_Shadow_Init(void); -extern void R_Sky_Init(void); -extern void GL_Surf_Init(void); -extern void R_Particles_Init(void); -extern void R_Explosion_Init(void); -extern void gl_backend_init(void); -extern void Sbar_Init(void); -extern void R_LightningBeams_Init(void); -extern void Mod_RenderInit(void); -extern void Font_Init(void); - void Render_Init(void) { gl_backend_init(); @@ -4427,7 +4470,11 @@ void GL_Init (void) VID_CheckExtensions(); // LordHavoc: report supported extensions +#ifdef CONFIG_MENU Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions ); +#else + Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions ); +#endif // clear to black (loading plaque will be seen over this) GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128); @@ -4562,12 +4609,12 @@ void R_FrameData_Reset(void) } } -void R_FrameData_Resize(void) +static void R_FrameData_Resize(qboolean mustgrow) { size_t wantedsize; wantedsize = (size_t)(r_framedatasize.value * 1024*1024); wantedsize = bound(65536, wantedsize, 1000*1024*1024); - if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize) + if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow) { r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize); newmem->wantedsize = wantedsize; @@ -4582,7 +4629,7 @@ void R_FrameData_Resize(void) void R_FrameData_NewFrame(void) { - R_FrameData_Resize(); + R_FrameData_Resize(false); if (!r_framedata_mem) return; // if we ran out of space on the last frame, free the old memory now @@ -4601,6 +4648,7 @@ void R_FrameData_NewFrame(void) void *R_FrameData_Alloc(size_t size) { void *data; + float newvalue; // align to 16 byte boundary - the data pointer is already aligned, so we // only need to ensure the size of every allocation is also aligned @@ -4609,16 +4657,18 @@ void *R_FrameData_Alloc(size_t size) while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size) { // emergency - we ran out of space, allocate more memory - Cvar_SetValueQuick(&r_framedatasize, bound(0.25f, r_framedatasize.value * 2.0f, 128.0f)); - R_FrameData_Resize(); + newvalue = bound(0.25f, r_framedatasize.value * 2.0f, 256.0f); + // this might not be a growing it, but we'll allocate another buffer every time + Cvar_SetValueQuick(&r_framedatasize, newvalue); + R_FrameData_Resize(true); } data = r_framedata_mem->data + r_framedata_mem->current; r_framedata_mem->current += size; // count the usage for stats - r_refdef.stats.framedatacurrent = max(r_refdef.stats.framedatacurrent, (int)r_framedata_mem->current); - r_refdef.stats.framedatasize = max(r_refdef.stats.framedatasize, (int)r_framedata_mem->size); + r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current); + r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size); return (void *)data; } @@ -4647,6 +4697,160 @@ void R_FrameData_ReturnToMark(void) //================================================================================== +// avoid reusing the same buffer objects on consecutive frames +#define R_BUFFERDATA_CYCLE 3 + +typedef struct r_bufferdata_buffer_s +{ + struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame + size_t size; // how much usable space + size_t current; // how much space in use + r_meshbuffer_t *buffer; // the buffer itself +} +r_bufferdata_buffer_t; + +static int r_bufferdata_cycle = 0; // incremented and wrapped each frame +static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT]; + +/// frees all dynamic buffers +void R_BufferData_Reset(void) +{ + int cycle, type; + r_bufferdata_buffer_t **p, *mem; + for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++) + { + for (type = 0;type < R_BUFFERDATA_COUNT;type++) + { + // free all buffers + p = &r_bufferdata_buffer[cycle][type]; + while (*p) + { + mem = *p; + *p = (*p)->purge; + if (mem->buffer) + R_Mesh_DestroyMeshBuffer(mem->buffer); + Mem_Free(mem); + } + } + } +} + +// resize buffer as needed (this actually makes a new one, the old one will be recycled next frame) +static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize) +{ + r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type]; + size_t size; + float newvalue = r_buffermegs[type].value; + + // increase the cvar if we have to (but only if we already have a mem) + if (mustgrow && mem) + newvalue *= 2.0f; + newvalue = bound(0.25f, newvalue, 256.0f); + while (newvalue * 1024*1024 < minsize) + newvalue *= 2.0f; + + // clamp the cvar to valid range + newvalue = bound(0.25f, newvalue, 256.0f); + if (r_buffermegs[type].value != newvalue) + Cvar_SetValueQuick(&r_buffermegs[type], newvalue); + + // calculate size in bytes + size = (size_t)(newvalue * 1024*1024); + size = bound(131072, size, 256*1024*1024); + + // allocate a new buffer if the size is different (purge old one later) + // or if we were told we must grow the buffer + if (!mem || mem->size != size || mustgrow) + { + mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem)); + mem->size = size; + mem->current = 0; + if (type == R_BUFFERDATA_VERTEX) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false); + else if (type == R_BUFFERDATA_INDEX16) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true); + else if (type == R_BUFFERDATA_INDEX32) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false); + else if (type == R_BUFFERDATA_UNIFORM) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false); + mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type]; + r_bufferdata_buffer[r_bufferdata_cycle][type] = mem; + } +} + +void R_BufferData_NewFrame(void) +{ + int type; + r_bufferdata_buffer_t **p, *mem; + // cycle to the next frame's buffers + r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE; + // if we ran out of space on the last time we used these buffers, free the old memory now + for (type = 0;type < R_BUFFERDATA_COUNT;type++) + { + if (r_bufferdata_buffer[r_bufferdata_cycle][type]) + { + R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072); + // free all but the head buffer, this is how we recycle obsolete + // buffers after they are no longer in use + p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge; + while (*p) + { + mem = *p; + *p = (*p)->purge; + if (mem->buffer) + R_Mesh_DestroyMeshBuffer(mem->buffer); + Mem_Free(mem); + } + // reset the current offset + r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0; + } + } +} + +r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset) +{ + r_bufferdata_buffer_t *mem; + int offset = 0; + int padsize; + + *returnbufferoffset = 0; + + // align size to a byte boundary appropriate for the buffer type, this + // makes all allocations have aligned start offsets + if (type == R_BUFFERDATA_UNIFORM) + padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1); + else + padsize = (datasize + 15) & ~15; + + // if we ran out of space in this buffer we must allocate a new one + 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) + R_BufferData_Resize(type, true, padsize); + + // if the resize did not give us enough memory, fail + 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) + Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n"); + + mem = r_bufferdata_buffer[r_bufferdata_cycle][type]; + offset = mem->current; + mem->current += padsize; + + // upload the data to the buffer at the chosen offset + if (offset == 0) + R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0); + R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset); + + // count the usage for stats + r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current); + r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size); + + // return the buffer offset + *returnbufferoffset = offset; + + return mem->buffer; +} + +//================================================================================== + // LordHavoc: animcache originally written by Echon, rewritten since then /** @@ -4667,16 +4871,28 @@ void R_AnimCache_ClearCache(void) { ent = r_refdef.scene.entities[i]; ent->animcache_vertex3f = NULL; + ent->animcache_vertex3f_vertexbuffer = NULL; + ent->animcache_vertex3f_bufferoffset = 0; ent->animcache_normal3f = NULL; + ent->animcache_normal3f_vertexbuffer = NULL; + ent->animcache_normal3f_bufferoffset = 0; ent->animcache_svector3f = NULL; + ent->animcache_svector3f_vertexbuffer = NULL; + ent->animcache_svector3f_bufferoffset = 0; ent->animcache_tvector3f = NULL; + ent->animcache_tvector3f_vertexbuffer = NULL; + ent->animcache_tvector3f_bufferoffset = 0; ent->animcache_vertexmesh = NULL; - ent->animcache_vertex3fbuffer = NULL; - ent->animcache_vertexmeshbuffer = NULL; + ent->animcache_vertexmesh_vertexbuffer = NULL; + ent->animcache_vertexmesh_bufferoffset = 0; + ent->animcache_skeletaltransform3x4 = NULL; + ent->animcache_skeletaltransform3x4buffer = NULL; + ent->animcache_skeletaltransform3x4offset = 0; + ent->animcache_skeletaltransform3x4size = 0; } } -void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices) +static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices) { int i; @@ -4686,10 +4902,13 @@ void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices) if (!ent->animcache_vertexmesh && ent->animcache_normal3f) ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices); - // TODO: upload vertex3f buffer? + // TODO: upload vertexbuffer? if (ent->animcache_vertexmesh) { - memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.vertexmesh, sizeof(r_vertexmesh_t)*numvertices); + r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1; + r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices); + memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices); for (i = 0;i < numvertices;i++) memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3])); if (ent->animcache_svector3f) @@ -4701,7 +4920,6 @@ void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices) if (ent->animcache_normal3f) for (i = 0;i < numvertices;i++) memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3])); - // TODO: upload vertexmeshbuffer? } } @@ -4709,37 +4927,65 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool { dp_model_t *model = ent->model; int numvertices; - // see if it's already cached this frame + + // see if this ent is worth caching + if (!model || !model->Draw || !model->AnimateVertices) + return false; + // nothing to cache if it contains no animations and has no skeleton + if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms)) + return false; + // see if it is already cached for gpuskeletal + if (ent->animcache_skeletaltransform3x4) + return false; + // see if it is already cached as a mesh if (ent->animcache_vertex3f) { - // add normals/tangents if needed (this only happens with multiple views, reflections, cameras, etc) + // check if we need to add normals or tangents + if (ent->animcache_normal3f) + wantnormals = false; + if (ent->animcache_svector3f) + wanttangents = false; + if (!wantnormals && !wanttangents) + return false; + } + + // check which kind of cache we need to generate + if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub) + { + // cache the skeleton so the vertex shader can use it + r_refdef.stats[r_stat_animcache_skeletal_count] += 1; + r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones; + r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones); + ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones); + Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); + // note: this can fail if the buffer is at the grow limit + ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones; + ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset); + } + else if (ent->animcache_vertex3f) + { + // mesh was already cached but we may need to add normals/tangents + // (this only happens with multiple views, reflections, cameras, etc) if (wantnormals || wanttangents) { - if (ent->animcache_normal3f) - wantnormals = false; - if (ent->animcache_svector3f) - wanttangents = false; - if (wantnormals || wanttangents) + numvertices = model->surfmesh.num_vertices; + if (wantnormals) + ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + if (wanttangents) { - numvertices = model->surfmesh.num_vertices; - if (wantnormals) - ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); - if (wanttangents) - { - ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); - ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); - } - model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL); - R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices); + ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); } + model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL); + R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices); + r_refdef.stats[r_stat_animcache_shade_count] += 1; + r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices); } } else { - // see if this ent is worth caching - if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices) - return false; - // get some memory for this entity and generate mesh data + // generate mesh cache numvertices = model->surfmesh.num_vertices; ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); if (wantnormals) @@ -4751,6 +4997,15 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool } model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f); R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices); + if (wantnormals || wanttangents) + { + r_refdef.stats[r_stat_animcache_shade_count] += 1; + r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices); + } + r_refdef.stats[r_stat_animcache_shape_count] += 1; + r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices); } return true; } @@ -4805,12 +5060,12 @@ static void R_View_UpdateEntityLighting (void) { ent = r_refdef.scene.entities[i]; - // skip unseen models and models that updated by CSQC - if ((!r_refdef.viewcache.entityvisible[i] && skipunseen) || ent->flags & RENDER_CUSTOMIZEDMODELLIGHT) + // skip unseen models + if ((!r_refdef.viewcache.entityvisible[i] && skipunseen)) continue; // skip bsp models - if (ent->model && ent->model->brush.num_leafs) + if (ent->model && ent->model == cl.worldmodel) { // TODO: use modellight for r_ambient settings on world? VectorSet(ent->modellight_ambient, 0, 0, 0); @@ -4818,74 +5073,83 @@ static void R_View_UpdateEntityLighting (void) VectorSet(ent->modellight_lightdir, 0, 0, 1); continue; } - - // fetch the lighting from the worldmodel data - VectorClear(ent->modellight_ambient); - VectorClear(ent->modellight_diffuse); - VectorClear(tempdiffusenormal); - if (ent->flags & RENDER_LIGHT) + + if (ent->flags & RENDER_CUSTOMIZEDMODELLIGHT) { - vec3_t org; - Matrix4x4_OriginFromMatrix(&ent->matrix, org); - - // complete lightning for lit sprites - // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)? - if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT)) + // aleady updated by CSQC + // TODO: force modellight on BSP models in this case? + VectorCopy(ent->modellight_lightdir, tempdiffusenormal); + } + else + { + // fetch the lighting from the worldmodel data + VectorClear(ent->modellight_ambient); + VectorClear(ent->modellight_diffuse); + VectorClear(tempdiffusenormal); + if (ent->flags & RENDER_LIGHT) { - if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites - org[2] = org[2] + r_overheadsprites_pushback.value; - R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); - } - else - R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP); + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); - if(ent->flags & RENDER_EQUALIZE) - { - // first fix up ambient lighting... - if(r_equalize_entities_minambient.value > 0) + // complete lightning for lit sprites + // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)? + if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT)) { - fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; - if(fd > 0) + if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites + org[2] = org[2] + r_overheadsprites_pushback.value; + R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); + } + else + R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP); + + if(ent->flags & RENDER_EQUALIZE) + { + // first fix up ambient lighting... + if(r_equalize_entities_minambient.value > 0) { - fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]); - if(fa < r_equalize_entities_minambient.value * fd) + fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; + if(fd > 0) { - // solve: - // fa'/fd' = minambient - // fa'+0.25*fd' = fa+0.25*fd - // ... - // fa' = fd' * minambient - // fd'*(0.25+minambient) = fa+0.25*fd - // ... - // fd' = (fa+0.25*fd) * 1 / (0.25+minambient) - // fa' = (fa+0.25*fd) * minambient / (0.25+minambient) - // ... - fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value); - f = fdd / fd; // f>0 because all this is additive; f<1 because fddmodellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient); - VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse); + fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]); + if(fa < r_equalize_entities_minambient.value * fd) + { + // solve: + // fa'/fd' = minambient + // fa'+0.25*fd' = fa+0.25*fd + // ... + // fa' = fd' * minambient + // fd'*(0.25+minambient) = fa+0.25*fd + // ... + // fd' = (fa+0.25*fd) * 1 / (0.25+minambient) + // fa' = (fa+0.25*fd) * minambient / (0.25+minambient) + // ... + fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value); + f = fdd / fd; // f>0 because all this is additive; f<1 because fddmodellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient); + VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse); + } } } - } - if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0) - { - fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]; - fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; - f = fa + 0.25 * fd; - if(f > 0) + if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0) { - // adjust brightness and saturation to target - avg[0] = avg[1] = avg[2] = fa / f; - VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient); - avg[0] = avg[1] = avg[2] = fd / f; - VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse); + fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]; + fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; + f = fa + 0.25 * fd; + if(f > 0) + { + // adjust brightness and saturation to target + avg[0] = avg[1] = avg[2] = fa / f; + VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient); + avg[0] = avg[1] = avg[2] = fd / f; + VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse); + } } } } + else // highly rare + VectorSet(ent->modellight_ambient, 1, 1, 1); } - else // highly rare - VectorSet(ent->modellight_ambient, 1, 1, 1); // move the light direction into modelspace coordinates for lighting code Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir); @@ -4946,8 +5210,8 @@ static void R_View_UpdateEntityVisible (void) entity_render_t *ent; renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) - : r_waterstate.hideplayer ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) - : (chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL + : r_fb.water.hideplayer ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) + : (chase_active.integer || r_fb.water.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL; if (!r_drawviewmodel.integer) renderimask |= RENDER_VIEWMODEL; @@ -4998,7 +5262,7 @@ static void R_View_UpdateEntityVisible (void) } /// only used if skyrendermasked, and normally returns false -int R_DrawBrushModelsSky (void) +static int R_DrawBrushModelsSky (void) { int i, sky; entity_render_t *ent; @@ -5028,7 +5292,7 @@ static void R_DrawModels(void) if (!r_refdef.viewcache.entityvisible[i]) continue; ent = r_refdef.scene.entities[i]; - r_refdef.stats.entities++; + r_refdef.stats[r_stat_entities]++; /* if (ent->model && !strncmp(ent->model->name, "models/proto_", 13)) { @@ -5339,29 +5603,27 @@ static void R_View_SetFrustum(const int *scissor) //PlaneClassify(&frustum[4]); } -void R_View_UpdateWithScissor(const int *myscissor) +static void R_View_UpdateWithScissor(const int *myscissor) { R_Main_ResizeViewCache(); R_View_SetFrustum(myscissor); R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); R_View_UpdateEntityLighting(); - R_AnimCache_CacheVisibleEntities(); } -void R_View_Update(void) +static void R_View_Update(void) { R_Main_ResizeViewCache(); R_View_SetFrustum(NULL); R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); R_View_UpdateEntityLighting(); - R_AnimCache_CacheVisibleEntities(); } float viewscalefpsadjusted = 1.0f; -void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight) +static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight) { float scale = r_viewscale.value * sqrt(viewscalefpsadjusted); scale = bound(0.03125f, scale, 1.0f); @@ -5369,19 +5631,11 @@ void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight) *outheight = (int)ceil(height * scale); } -void R_Mesh_SetMainRenderTargets(void) -{ - if (r_bloomstate.fbo_framebuffer) - R_Mesh_SetRenderTargets(r_bloomstate.fbo_framebuffer, r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL); - else - R_Mesh_ResetRenderTargets(); -} - -void R_SetupView(qboolean allowwaterclippingplane) +void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) { const float *customclipplane = NULL; float plane[4]; - int scaledwidth, scaledheight; + int /*rtwidth,*/ rtheight, scaledwidth, scaledheight; if (r_refdef.view.useclipplane && allowwaterclippingplane) { // LordHavoc: couldn't figure out how to make this approach the @@ -5396,14 +5650,17 @@ void R_SetupView(qboolean allowwaterclippingplane) if(vid.renderpath != RENDERPATH_SOFT) customclipplane = plane; } + //rtwidth = fbo ? R_TextureWidth(depthtexture ? depthtexture : colortexture) : vid.width; + rtheight = fbo ? R_TextureHeight(depthtexture ? depthtexture : colortexture) : vid.height; + R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &scaledwidth, &scaledheight); if (!r_refdef.view.useperspective) - R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane); + R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane); else if (vid.stencil && r_useinfinitefarclip.integer) - R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane); + R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane); else - R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane); - R_Mesh_SetMainRenderTargets(); + R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane); + R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL); R_SetViewport(&r_refdef.view.viewport); if (r_refdef.view.useclipplane && allowwaterclippingplane && vid.renderpath == RENDERPATH_SOFT) { @@ -5445,7 +5702,9 @@ void R_EntityMatrix(const matrix4x4_t *matrix) case RENDERPATH_GL11: case RENDERPATH_GL13: case RENDERPATH_GLES1: +#ifndef USE_GLES2 qglLoadMatrixf(gl_modelview16f);CHECKGLERROR +#endif break; case RENDERPATH_SOFT: DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f); @@ -5460,14 +5719,15 @@ void R_EntityMatrix(const matrix4x4_t *matrix) } } -void R_ResetViewRendering2D(void) +void R_ResetViewRendering2D_Common(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, float x2, float y2) { r_viewport_t viewport; - DrawQ_Finish(); + + CHECKGLERROR // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom - R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL); - R_Mesh_ResetRenderTargets(); + R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, x2, y2, -10, 100, NULL); + R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL); R_SetViewport(&viewport); GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); GL_Color(1, 1, 1, 1); @@ -5498,13 +5758,22 @@ void R_ResetViewRendering2D(void) break; } GL_CullFace(GL_NONE); + + CHECKGLERROR +} + +void R_ResetViewRendering2D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + DrawQ_Finish(); + + R_ResetViewRendering2D_Common(fbo, depthtexture, colortexture, 1, 1); } -void R_ResetViewRendering3D(void) +void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) { DrawQ_Finish(); - R_SetupView(true); + R_SetupView(true, fbo, depthtexture, colortexture); GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); GL_Color(1, 1, 1, 1); GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); @@ -5541,7 +5810,7 @@ void R_ResetViewRendering3D(void) R_RenderView_UpdateViewVectors ================ */ -static void R_RenderView_UpdateViewVectors(void) +void R_RenderView_UpdateViewVectors(void) { // break apart the view matrix into vectors for various purposes // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong @@ -5552,14 +5821,15 @@ static void R_RenderView_UpdateViewVectors(void) Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix); } -void R_RenderScene(void); -void R_RenderWaterPlanes(void); +void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); static void R_Water_StartFrame(void) { int i; int waterwidth, waterheight, texturewidth, textureheight, camerawidth, cameraheight; r_waterstate_waterplane_t *p; + qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2; if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d) return; @@ -5596,55 +5866,64 @@ static void R_Water_StartFrame(void) } else { - for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2); - for (textureheight = 1;textureheight < waterheight;textureheight *= 2); - for (camerawidth = 1;camerawidth <= waterwidth; camerawidth *= 2); camerawidth /= 2; - for (cameraheight = 1;cameraheight <= waterheight;cameraheight *= 2); cameraheight /= 2; + for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2); + for (textureheight = 1;textureheight < waterheight;textureheight *= 2); + for (camerawidth = 1;camerawidth * 2 <= waterwidth ;camerawidth *= 2); + for (cameraheight = 1;cameraheight * 2 <= waterheight;cameraheight *= 2); } // allocate textures as needed - if (r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight || r_waterstate.camerawidth != camerawidth || r_waterstate.cameraheight != cameraheight) + if (r_fb.water.texturewidth != texturewidth || r_fb.water.textureheight != textureheight || r_fb.water.camerawidth != camerawidth || r_fb.water.cameraheight != cameraheight || (r_fb.depthtexture && !usewaterfbo)) { - r_waterstate.maxwaterplanes = MAX_WATERPLANES; - for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++) + r_fb.water.maxwaterplanes = MAX_WATERPLANES; + for (i = 0, p = r_fb.water.waterplanes;i < r_fb.water.maxwaterplanes;i++, p++) { if (p->texture_refraction) R_FreeTexture(p->texture_refraction); p->texture_refraction = NULL; + if (p->fbo_refraction) + R_Mesh_DestroyFramebufferObject(p->fbo_refraction); + p->fbo_refraction = 0; if (p->texture_reflection) R_FreeTexture(p->texture_reflection); p->texture_reflection = NULL; + if (p->fbo_reflection) + R_Mesh_DestroyFramebufferObject(p->fbo_reflection); + p->fbo_reflection = 0; if (p->texture_camera) R_FreeTexture(p->texture_camera); p->texture_camera = NULL; + if (p->fbo_camera) + R_Mesh_DestroyFramebufferObject(p->fbo_camera); + p->fbo_camera = 0; } - memset(&r_waterstate, 0, sizeof(r_waterstate)); - r_waterstate.texturewidth = texturewidth; - r_waterstate.textureheight = textureheight; - r_waterstate.camerawidth = camerawidth; - r_waterstate.cameraheight = cameraheight; + memset(&r_fb.water, 0, sizeof(r_fb.water)); + r_fb.water.texturewidth = texturewidth; + r_fb.water.textureheight = textureheight; + r_fb.water.camerawidth = camerawidth; + r_fb.water.cameraheight = cameraheight; } - if (r_waterstate.texturewidth) + if (r_fb.water.texturewidth) { int scaledwidth, scaledheight; - r_waterstate.enabled = true; + r_fb.water.enabled = true; - // when doing a reduced render (HDR) we want to use a smaller area - r_waterstate.waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width); - r_waterstate.waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height); - R_GetScaledViewSize(r_waterstate.waterwidth, r_waterstate.waterheight, &scaledwidth, &scaledheight); + // water resolution is usually reduced + r_fb.water.waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width); + r_fb.water.waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height); + R_GetScaledViewSize(r_fb.water.waterwidth, r_fb.water.waterheight, &scaledwidth, &scaledheight); // set up variables that will be used in shader setup - r_waterstate.screenscale[0] = 0.5f * (float)scaledwidth / (float)r_waterstate.texturewidth; - r_waterstate.screenscale[1] = 0.5f * (float)scaledheight / (float)r_waterstate.textureheight; - r_waterstate.screencenter[0] = 0.5f * (float)scaledwidth / (float)r_waterstate.texturewidth; - r_waterstate.screencenter[1] = 0.5f * (float)scaledheight / (float)r_waterstate.textureheight; + r_fb.water.screenscale[0] = 0.5f * (float)scaledwidth / (float)r_fb.water.texturewidth; + r_fb.water.screenscale[1] = 0.5f * (float)scaledheight / (float)r_fb.water.textureheight; + r_fb.water.screencenter[0] = 0.5f * (float)scaledwidth / (float)r_fb.water.texturewidth; + r_fb.water.screencenter[1] = 0.5f * (float)scaledheight / (float)r_fb.water.textureheight; } - r_waterstate.maxwaterplanes = MAX_WATERPLANES; - r_waterstate.numwaterplanes = 0; + r_fb.water.maxwaterplanes = MAX_WATERPLANES; + r_fb.water.numwaterplanes = 0; } void R_Water_AddWaterPlane(msurface_t *surface, int entno) @@ -5700,7 +5979,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno) // find a matching plane if there is one bestplaneindex = -1; bestplanescore = 1048576.0f; - for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) { if(p->camera_entity == t->camera_entity) { @@ -5713,14 +5992,14 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno) } } planeindex = bestplaneindex; - p = r_waterstate.waterplanes + planeindex; + p = r_fb.water.waterplanes + planeindex; // if this surface does not fit any known plane rendered this frame, add one - if ((planeindex < 0 || bestplanescore > 0.001f) && r_waterstate.numwaterplanes < r_waterstate.maxwaterplanes) + if ((planeindex < 0 || bestplanescore > 0.001f) && r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes) { // store the new plane - planeindex = r_waterstate.numwaterplanes++; - p = r_waterstate.waterplanes + planeindex; + planeindex = r_fb.water.numwaterplanes++; + p = r_fb.water.waterplanes + planeindex; p->plane = plane; // clear materialflags and pvs p->materialflags = 0; @@ -5756,7 +6035,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno) extern cvar_t r_drawparticles; extern cvar_t r_drawdecals; -static void R_Water_ProcessPlanes(void) +static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) { int myscissor[4]; r_refdef_view_t originalview; @@ -5764,6 +6043,8 @@ static void R_Water_ProcessPlanes(void) 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; r_waterstate_waterplane_t *p; vec3_t visorigin; + qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2; + char vabuf[1024]; originalview = r_refdef.view; @@ -5792,48 +6073,69 @@ static void R_Water_ProcessPlanes(void) } // make sure enough textures are allocated - for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) { if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) { if (!p->texture_refraction) - p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_refraction", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_refraction", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); if (!p->texture_refraction) goto error; + if (usewaterfbo) + { + if (r_fb.water.depthtexture == NULL) + r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + if (p->fbo_refraction == 0) + p->fbo_refraction = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_refraction, NULL, NULL, NULL); + } } else if (p->materialflags & MATERIALFLAG_CAMERA) { if (!p->texture_camera) - p->texture_camera = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_camera", planeindex), r_waterstate.camerawidth, r_waterstate.cameraheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCELINEAR, -1, NULL); + p->texture_camera = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_camera", planeindex), r_fb.water.camerawidth, r_fb.water.cameraheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR, -1, NULL); if (!p->texture_camera) goto error; + if (usewaterfbo) + { + if (r_fb.water.depthtexture == NULL) + r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + if (p->fbo_camera == 0) + p->fbo_camera = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_camera, NULL, NULL, NULL); + } } if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) { if (!p->texture_reflection) - p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_reflection", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_reflection", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); if (!p->texture_reflection) goto error; + if (usewaterfbo) + { + if (r_fb.water.depthtexture == NULL) + r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + if (p->fbo_reflection == 0) + p->fbo_reflection = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_reflection, NULL, NULL, NULL); + } } } // render views r_refdef.view = originalview; r_refdef.view.showdebug = false; - r_refdef.view.width = r_waterstate.waterwidth; - r_refdef.view.height = r_waterstate.waterheight; + r_refdef.view.width = r_fb.water.waterwidth; + r_refdef.view.height = r_fb.water.waterheight; r_refdef.view.useclipplane = true; myview = r_refdef.view; - r_waterstate.renderingscene = true; - for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) + r_fb.water.renderingscene = true; + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) { if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) { r_refdef.view = myview; if(r_water_scissormode.integer) { - R_SetupView(true); + R_SetupView(true, p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection); if(R_ScissorForBBox(p->mins, p->maxs, myscissor)) continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible } @@ -5855,19 +6157,21 @@ static void R_Water_ProcessPlanes(void) memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes); } - r_waterstate.hideplayer = r_water_hideplayer.integer >= 2; - R_ResetViewRendering3D(); + r_fb.water.hideplayer = r_water_hideplayer.integer >= 2; + R_ResetViewRendering3D(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection); R_ClearScreen(r_refdef.fogenabled); if(r_water_scissormode.integer & 2) R_View_UpdateWithScissor(myscissor); else R_View_Update(); + R_AnimCache_CacheVisibleEntities(); if(r_water_scissormode.integer & 1) GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); - R_RenderScene(); + R_RenderScene(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection); - R_Mesh_CopyToTexture(p->texture_reflection, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); - r_waterstate.hideplayer = false; + if (!p->fbo_reflection) + R_Mesh_CopyToTexture(p->texture_reflection, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_fb.water.hideplayer = false; } // render the normal view scene and copy into texture @@ -5877,12 +6181,12 @@ static void R_Water_ProcessPlanes(void) r_refdef.view = myview; if(r_water_scissormode.integer) { - R_SetupView(true); + R_SetupView(true, p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction); if(R_ScissorForBBox(p->mins, p->maxs, myscissor)) continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible } - r_waterstate.hideplayer = r_water_hideplayer.integer >= 1; + r_fb.water.hideplayer = r_water_hideplayer.integer >= 1; r_refdef.view.clipplane = p->plane; VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); @@ -5891,7 +6195,7 @@ static void R_Water_ProcessPlanes(void) if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity) { // we need to perform a matrix transform to render the view... so let's get the transformation matrix - r_waterstate.renderingrefraction = false; // we don't want to hide the player model from these ones + r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin); R_RenderView_UpdateViewVectors(); if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS) @@ -5903,18 +6207,20 @@ static void R_Water_ProcessPlanes(void) PlaneClassify(&r_refdef.view.clipplane); - R_ResetViewRendering3D(); + R_ResetViewRendering3D(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction); R_ClearScreen(r_refdef.fogenabled); if(r_water_scissormode.integer & 2) R_View_UpdateWithScissor(myscissor); else R_View_Update(); + R_AnimCache_CacheVisibleEntities(); if(r_water_scissormode.integer & 1) GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); - R_RenderScene(); + R_RenderScene(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction); - R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); - r_waterstate.hideplayer = false; + if (!p->fbo_refraction) + R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_fb.water.hideplayer = false; } else if (p->materialflags & MATERIALFLAG_CAMERA) { @@ -5924,8 +6230,8 @@ static void R_Water_ProcessPlanes(void) VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; - r_refdef.view.width = r_waterstate.camerawidth; - r_refdef.view.height = r_waterstate.cameraheight; + r_refdef.view.width = r_fb.water.camerawidth; + r_refdef.view.height = r_fb.water.cameraheight; r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0); r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0); r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView @@ -5957,28 +6263,32 @@ static void R_Water_ProcessPlanes(void) PlaneClassify(&r_refdef.view.clipplane); - r_waterstate.hideplayer = false; + r_fb.water.hideplayer = false; - R_ResetViewRendering3D(); + R_ResetViewRendering3D(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera); R_ClearScreen(r_refdef.fogenabled); R_View_Update(); - R_RenderScene(); + R_AnimCache_CacheVisibleEntities(); + R_RenderScene(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera); - R_Mesh_CopyToTexture(p->texture_camera, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); - r_waterstate.hideplayer = false; + if (!p->fbo_camera) + R_Mesh_CopyToTexture(p->texture_camera, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_fb.water.hideplayer = false; } } if(vid.renderpath==RENDERPATH_SOFT) DPSOFTRAST_ClipPlane(0, 0, 0, 1); - r_waterstate.renderingscene = false; + r_fb.water.renderingscene = false; r_refdef.view = originalview; - R_ResetViewRendering3D(); - R_ClearScreen(r_refdef.fogenabled); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + if (!r_fb.water.depthtexture) + R_ClearScreen(r_refdef.fogenabled); R_View_Update(); + R_AnimCache_CacheVisibleEntities(); goto finish; error: r_refdef.view = originalview; - r_waterstate.renderingscene = false; + r_fb.water.renderingscene = false; Cvar_SetValueQuick(&r_water, 0); Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n"); finish: @@ -6000,11 +6310,37 @@ finish: } } -void R_Bloom_StartFrame(void) +static void R_Bloom_StartFrame(void) { + int i; int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight; int viewwidth, viewheight; - textype_t textype; + qboolean useviewfbo = r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2; + textype_t textype = TEXTYPE_COLORBUFFER; + + switch (vid.renderpath) + { + case RENDERPATH_GL20: + r_fb.usedepthtextures = r_usedepthtextures.integer != 0; + if (vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two) + { + if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F; + if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F; + } + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + r_fb.usedepthtextures = false; + break; + case RENDERPATH_SOFT: + r_fb.usedepthtextures = true; + break; + } if (r_viewscale_fpsscaling.integer) { @@ -6042,145 +6378,147 @@ void R_Bloom_StartFrame(void) // set bloomwidth and bloomheight to the bloom resolution that will be // used (often less than the screen resolution for faster rendering) - r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height); - r_bloomstate.bloomheight = r_bloomstate.bloomwidth * vid.height / vid.width; - r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, vid.height); - r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, (int)vid.maxtexturesize_2d); - r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, (int)vid.maxtexturesize_2d); + r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width); + r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width; + r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height); + r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d); + r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d); // calculate desired texture sizes if (vid.support.arb_texture_non_power_of_two) { screentexturewidth = vid.width; screentextureheight = vid.height; - bloomtexturewidth = r_bloomstate.bloomwidth; - bloomtextureheight = r_bloomstate.bloomheight; + bloomtexturewidth = r_fb.bloomwidth; + bloomtextureheight = r_fb.bloomheight; } else { - for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2); - for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2); - for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2); - for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2); + for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2); + for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2); + for (bloomtexturewidth = 1;bloomtexturewidth < r_fb.bloomwidth ;bloomtexturewidth *= 2); + for (bloomtextureheight = 1;bloomtextureheight < r_fb.bloomheight;bloomtextureheight *= 2); } - if ((r_hdr.integer || 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)) + 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)) { - Cvar_SetValueQuick(&r_hdr, 0); Cvar_SetValueQuick(&r_bloom, 0); Cvar_SetValueQuick(&r_motionblur, 0); Cvar_SetValueQuick(&r_damageblur, 0); } - if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)) && r_viewfbo.integer < 1 && r_viewscale.value == 1.0f && !r_viewscale_fpsscaling.integer) - screentexturewidth = screentextureheight = 0; - if (!r_hdr.integer && !r_bloom.integer) - bloomtexturewidth = bloomtextureheight = 0; + if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) + && !r_bloom.integer + && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)) + && !useviewfbo + && r_viewscale.value == 1.0f + && !r_viewscale_fpsscaling.integer) + screentexturewidth = screentextureheight = 0; + if (!r_bloom.integer) + bloomtexturewidth = bloomtextureheight = 0; + + // allocate textures as needed + if (r_fb.screentexturewidth != screentexturewidth + || r_fb.screentextureheight != screentextureheight + || r_fb.bloomtexturewidth != bloomtexturewidth + || r_fb.bloomtextureheight != bloomtextureheight + || r_fb.textype != textype + || useviewfbo != (r_fb.fbo != 0)) + { + for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++) + { + if (r_fb.bloomtexture[i]) + R_FreeTexture(r_fb.bloomtexture[i]); + r_fb.bloomtexture[i] = NULL; + + if (r_fb.bloomfbo[i]) + R_Mesh_DestroyFramebufferObject(r_fb.bloomfbo[i]); + r_fb.bloomfbo[i] = 0; + } + + if (r_fb.fbo) + R_Mesh_DestroyFramebufferObject(r_fb.fbo); + r_fb.fbo = 0; + + if (r_fb.colortexture) + R_FreeTexture(r_fb.colortexture); + r_fb.colortexture = NULL; + + if (r_fb.depthtexture) + R_FreeTexture(r_fb.depthtexture); + r_fb.depthtexture = NULL; + + if (r_fb.ghosttexture) + R_FreeTexture(r_fb.ghosttexture); + r_fb.ghosttexture = NULL; + + r_fb.screentexturewidth = screentexturewidth; + r_fb.screentextureheight = screentextureheight; + r_fb.bloomtexturewidth = bloomtexturewidth; + r_fb.bloomtextureheight = bloomtextureheight; + r_fb.textype = textype; - textype = TEXTYPE_COLORBUFFER; - switch (vid.renderpath) - { - case RENDERPATH_GL20: - case RENDERPATH_GLES2: - if (vid.support.ext_framebuffer_object) + if (r_fb.screentexturewidth && r_fb.screentextureheight) { - if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F; - if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F; + if (r_motionblur.value > 0 || r_damageblur.value > 0) + 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); + r_fb.ghosttexture_valid = false; + r_fb.colortexture = R_LoadTexture2D(r_main_texturepool, "framebuffercolor", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + if (useviewfbo) + { + r_fb.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "framebufferdepth", r_fb.screentexturewidth, r_fb.screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + r_fb.fbo = R_Mesh_CreateFramebufferObject(r_fb.depthtexture, r_fb.colortexture, NULL, NULL, NULL); + R_Mesh_SetRenderTargets(r_fb.fbo, r_fb.depthtexture, r_fb.colortexture, NULL, NULL, NULL); + } } - break; - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GLES1: - case RENDERPATH_D3D9: - case RENDERPATH_D3D10: - case RENDERPATH_D3D11: - case RENDERPATH_SOFT: - break; - } - // allocate textures as needed - if (r_bloomstate.screentexturewidth != screentexturewidth - || r_bloomstate.screentextureheight != screentextureheight - || r_bloomstate.bloomtexturewidth != bloomtexturewidth - || r_bloomstate.bloomtextureheight != bloomtextureheight - || r_bloomstate.texturetype != textype - || r_bloomstate.viewfbo != r_viewfbo.integer) - { - if (r_bloomstate.texture_bloom) - R_FreeTexture(r_bloomstate.texture_bloom); - r_bloomstate.texture_bloom = NULL; - if (r_bloomstate.texture_screen) - R_FreeTexture(r_bloomstate.texture_screen); - r_bloomstate.texture_screen = NULL; - if (r_bloomstate.fbo_framebuffer) - R_Mesh_DestroyFramebufferObject(r_bloomstate.fbo_framebuffer); - r_bloomstate.fbo_framebuffer = 0; - if (r_bloomstate.texture_framebuffercolor) - R_FreeTexture(r_bloomstate.texture_framebuffercolor); - r_bloomstate.texture_framebuffercolor = NULL; - if (r_bloomstate.texture_framebufferdepth) - R_FreeTexture(r_bloomstate.texture_framebufferdepth); - r_bloomstate.texture_framebufferdepth = NULL; - r_bloomstate.screentexturewidth = screentexturewidth; - r_bloomstate.screentextureheight = screentextureheight; - if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight) - r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); - if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object) - { - // FIXME: choose depth bits based on a cvar - r_bloomstate.texture_framebufferdepth = R_LoadTextureShadowMap2D(r_main_texturepool, "framebufferdepth", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, 24, false); - r_bloomstate.texture_framebuffercolor = R_LoadTexture2D(r_main_texturepool, "framebuffercolor", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); - r_bloomstate.fbo_framebuffer = R_Mesh_CreateFramebufferObject(r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL); - R_Mesh_SetRenderTargets(r_bloomstate.fbo_framebuffer, r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL); -#ifndef USE_GLES2 - // render depth into one texture and normalmap into the other - if (qglDrawBuffer) + if (r_fb.bloomtexturewidth && r_fb.bloomtextureheight) + { + for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++) { - int status; - qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR - qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR - status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER);CHECKGLERROR - if (status != GL_FRAMEBUFFER_COMPLETE) - Con_Printf("R_Bloom_StartFrame: glCheckFramebufferStatusEXT returned %i\n", status); + r_fb.bloomtexture[i] = R_LoadTexture2D(r_main_texturepool, "framebufferbloom", r_fb.bloomtexturewidth, r_fb.bloomtextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + if (useviewfbo) + r_fb.bloomfbo[i] = R_Mesh_CreateFramebufferObject(NULL, r_fb.bloomtexture[i], NULL, NULL, NULL); } -#endif } - r_bloomstate.bloomtexturewidth = bloomtexturewidth; - r_bloomstate.bloomtextureheight = bloomtextureheight; - if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight) - r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); - r_bloomstate.viewfbo = r_viewfbo.integer; - r_bloomstate.texturetype = textype; } - // when doing a reduced render (HDR) we want to use a smaller area - r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.height); - r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_refdef.view.height / r_refdef.view.width; - r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_refdef.view.height); - r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, r_bloomstate.bloomtexturewidth); - r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_bloomstate.bloomtextureheight); + // bloom texture is a different resolution + r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width); + r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width; + r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height); + r_fb.bloomwidth = bound(1, r_fb.bloomwidth, r_fb.bloomtexturewidth); + r_fb.bloomheight = bound(1, r_fb.bloomheight, r_fb.bloomtextureheight); // set up a texcoord array for the full resolution screen image // (we have to keep this around to copy back during final render) - r_bloomstate.screentexcoord2f[0] = 0; - r_bloomstate.screentexcoord2f[1] = (float)viewheight / (float)r_bloomstate.screentextureheight; - r_bloomstate.screentexcoord2f[2] = (float)viewwidth / (float)r_bloomstate.screentexturewidth; - r_bloomstate.screentexcoord2f[3] = (float)viewheight / (float)r_bloomstate.screentextureheight; - r_bloomstate.screentexcoord2f[4] = (float)viewwidth / (float)r_bloomstate.screentexturewidth; - r_bloomstate.screentexcoord2f[5] = 0; - r_bloomstate.screentexcoord2f[6] = 0; - r_bloomstate.screentexcoord2f[7] = 0; + r_fb.screentexcoord2f[0] = 0; + r_fb.screentexcoord2f[1] = (float)viewheight / (float)r_fb.screentextureheight; + r_fb.screentexcoord2f[2] = (float)viewwidth / (float)r_fb.screentexturewidth; + r_fb.screentexcoord2f[3] = (float)viewheight / (float)r_fb.screentextureheight; + r_fb.screentexcoord2f[4] = (float)viewwidth / (float)r_fb.screentexturewidth; + r_fb.screentexcoord2f[5] = 0; + r_fb.screentexcoord2f[6] = 0; + r_fb.screentexcoord2f[7] = 0; + + if(r_fb.fbo) + { + for (i = 1;i < 8;i += 2) + { + r_fb.screentexcoord2f[i] += 1 - (float)(viewheight + r_refdef.view.y) / (float)r_fb.screentextureheight; + } + } // set up a texcoord array for the reduced resolution bloom image // (which will be additive blended over the screen image) - r_bloomstate.bloomtexcoord2f[0] = 0; - r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; - r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; - r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; - r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; - r_bloomstate.bloomtexcoord2f[5] = 0; - r_bloomstate.bloomtexcoord2f[6] = 0; - r_bloomstate.bloomtexcoord2f[7] = 0; + r_fb.bloomtexcoord2f[0] = 0; + r_fb.bloomtexcoord2f[1] = (float)r_fb.bloomheight / (float)r_fb.bloomtextureheight; + r_fb.bloomtexcoord2f[2] = (float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth; + r_fb.bloomtexcoord2f[3] = (float)r_fb.bloomheight / (float)r_fb.bloomtextureheight; + r_fb.bloomtexcoord2f[4] = (float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth; + r_fb.bloomtexcoord2f[5] = 0; + r_fb.bloomtexcoord2f[6] = 0; + r_fb.bloomtexcoord2f[7] = 0; switch(vid.renderpath) { @@ -6194,39 +6532,46 @@ void R_Bloom_StartFrame(void) case RENDERPATH_D3D9: case RENDERPATH_D3D10: case RENDERPATH_D3D11: + for (i = 0;i < 4;i++) { - int i; - for (i = 0;i < 4;i++) - { - r_bloomstate.screentexcoord2f[i*2+0] += 0.5f / (float)r_bloomstate.screentexturewidth; - r_bloomstate.screentexcoord2f[i*2+1] += 0.5f / (float)r_bloomstate.screentextureheight; - r_bloomstate.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_bloomstate.bloomtexturewidth; - r_bloomstate.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_bloomstate.bloomtextureheight; - } + r_fb.screentexcoord2f[i*2+0] += 0.5f / (float)r_fb.screentexturewidth; + r_fb.screentexcoord2f[i*2+1] += 0.5f / (float)r_fb.screentextureheight; + r_fb.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_fb.bloomtexturewidth; + r_fb.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_fb.bloomtextureheight; } break; } - if ((r_hdr.integer || r_bloom.integer) && r_bloomstate.bloomwidth) - { - r_bloomstate.enabled = true; - r_bloomstate.hdr = r_hdr.integer != 0 && !r_bloomstate.fbo_framebuffer; - } - - R_Viewport_InitOrtho(&r_bloomstate.viewport, &identitymatrix, r_refdef.view.x, vid.height - r_bloomstate.bloomheight - r_refdef.view.y, r_bloomstate.bloomwidth, r_bloomstate.bloomheight, 0, 0, 1, 1, -10, 100, NULL); + R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL); - if (r_bloomstate.fbo_framebuffer) + if (r_fb.fbo) r_refdef.view.clear = true; } -void R_Bloom_CopyBloomTexture(float colorscale) +static void R_Bloom_MakeTexture(void) { - r_refdef.stats.bloom++; + int x, range, dir; + float xoffset, yoffset, r, brighten; + rtexture_t *intex; + float colorscale = r_bloom_colorscale.value; + + r_refdef.stats[r_stat_bloom]++; + +#if 0 + // this copy is unnecessary since it happens in R_BlendView already + if (!r_fb.fbo) + { + R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + } +#endif // scale down screen texture to the bloom texture size CHECKGLERROR - R_Mesh_SetMainRenderTargets(); - R_SetViewport(&r_bloomstate.viewport); + r_fb.bloomindex = 0; + R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); + R_SetViewport(&r_fb.bloomviewport); + GL_DepthTest(false); GL_BlendFunc(GL_ONE, GL_ZERO); GL_Color(colorscale, colorscale, colorscale, 1); // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that... @@ -6238,90 +6583,91 @@ void R_Bloom_CopyBloomTexture(float colorscale) case RENDERPATH_GLES1: case RENDERPATH_GLES2: case RENDERPATH_SOFT: - R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.screentexcoord2f); break; case RENDERPATH_D3D9: case RENDERPATH_D3D10: case RENDERPATH_D3D11: - R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_bloomstate.screentexcoord2f); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f); break; } // TODO: do boxfilter scale-down in shader? - R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1, false, true); + R_SetupShader_Generic(r_fb.colortexture, NULL, GL_MODULATE, 1, false, true, true); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); - r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; - - // we now have a bloom image in the framebuffer - // copy it into the bloom image texture for later processing - R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height); - r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height; -} - -void R_Bloom_CopyHDRTexture(void) -{ - R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); - r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; -} - -void R_Bloom_MakeTexture(void) -{ - int x, range, dir; - float xoffset, yoffset, r, brighten; - - r_refdef.stats.bloom++; + r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight; - R_ResetViewRendering2D(); - - // we have a bloom image in the framebuffer - CHECKGLERROR - R_SetViewport(&r_bloomstate.viewport); + // we now have a properly scaled bloom image + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + // copy it into the bloom texture + R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height; + } + // multiply bloom image by itself as many times as desired for (x = 1;x < min(r_bloom_colorexponent.value, 32);) { + intex = r_fb.bloomtexture[r_fb.bloomindex]; + r_fb.bloomindex ^= 1; + R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); x *= 2; - r = bound(0, r_bloom_colorexponent.value / x, 1); - GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); - GL_Color(r,r,r,1); - R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f); - R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1, false, true); + r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1 + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); // square it and multiply by two + GL_Color(r,r,r,1); // apply fix factor + } + else + { + if(x <= 2) + GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128); + GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it + GL_Color(1,1,1,1); // no fix factor supported here + } + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.bloomtexcoord2f); + R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); - r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight; - // copy the vertically blurred bloom view to a texture - R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height); - r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height; + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + // copy the darkened image to a texture + R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height; + } } - range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320; + range = r_bloom_blur.integer * r_fb.bloomwidth / 320; brighten = r_bloom_brighten.value; - if (r_bloomstate.hdr) - brighten *= r_hdr_range.value; brighten = sqrt(brighten); if(range >= 1) brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle" - R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1, false, true); for (dir = 0;dir < 2;dir++) { + intex = r_fb.bloomtexture[r_fb.bloomindex]; + r_fb.bloomindex ^= 1; + R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); // blend on at multiple vertical offsets to achieve a vertical blur // TODO: do offset blends using GLSL // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges GL_BlendFunc(GL_ONE, GL_ZERO); + R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false); for (x = -range;x <= range;x++) { if (!dir){xoffset = 0;yoffset = x;} else {xoffset = x;yoffset = 0;} - xoffset /= (float)r_bloomstate.bloomtexturewidth; - yoffset /= (float)r_bloomstate.bloomtextureheight; + xoffset /= (float)r_fb.bloomtexturewidth; + yoffset /= (float)r_fb.bloomtextureheight; // compute a texcoord array with the specified x and y offset - r_bloomstate.offsettexcoord2f[0] = xoffset+0; - r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; - r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; - r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; - r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; - r_bloomstate.offsettexcoord2f[5] = yoffset+0; - r_bloomstate.offsettexcoord2f[6] = xoffset+0; - r_bloomstate.offsettexcoord2f[7] = yoffset+0; + r_fb.offsettexcoord2f[0] = xoffset+r_fb.bloomtexcoord2f[0]; + r_fb.offsettexcoord2f[1] = yoffset+r_fb.bloomtexcoord2f[1]; + r_fb.offsettexcoord2f[2] = xoffset+r_fb.bloomtexcoord2f[2]; + r_fb.offsettexcoord2f[3] = yoffset+r_fb.bloomtexcoord2f[3]; + r_fb.offsettexcoord2f[4] = xoffset+r_fb.bloomtexcoord2f[4]; + r_fb.offsettexcoord2f[5] = yoffset+r_fb.bloomtexcoord2f[5]; + r_fb.offsettexcoord2f[6] = xoffset+r_fb.bloomtexcoord2f[6]; + r_fb.offsettexcoord2f[7] = yoffset+r_fb.bloomtexcoord2f[7]; // this r value looks like a 'dot' particle, fading sharply to // black at the edges // (probably not realistic but looks good enough) @@ -6331,83 +6677,28 @@ void R_Bloom_MakeTexture(void) if(range >= 1) r *= (1 - x*x/(float)(range*range)); GL_Color(r, r, r, 1); - R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.offsettexcoord2f); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); - r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight; GL_BlendFunc(GL_ONE, GL_ONE); } - // copy the vertically blurred bloom view to a texture - R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height); - r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height; + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + // copy the vertically or horizontally blurred bloom view to a texture + R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height; + } } } -void R_HDR_RenderBloomTexture(void) -{ - int oldwidth, oldheight; - float oldcolorscale; - qboolean oldwaterstate; - - oldwaterstate = r_waterstate.enabled; - oldcolorscale = r_refdef.view.colorscale; - oldwidth = r_refdef.view.width; - oldheight = r_refdef.view.height; - r_refdef.view.width = r_bloomstate.bloomwidth; - r_refdef.view.height = r_bloomstate.bloomheight; - - if(r_hdr.integer < 2) - r_waterstate.enabled = false; - - // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance. - // TODO: add exposure compensation features - // TODO: add fp16 framebuffer support (using GL_EXT_framebuffer_object) - - r_refdef.view.showdebug = false; - r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16); - - R_ResetViewRendering3D(); - - R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("HDRclear"); - - R_View_Update(); - if (r_timereport_active) - R_TimeReport("visibility"); - - // only do secondary renders with HDR if r_hdr is 2 or higher - r_waterstate.numwaterplanes = 0; - if (r_waterstate.enabled) - R_RenderWaterPlanes(); - - r_refdef.view.showdebug = true; - R_RenderScene(); - r_waterstate.numwaterplanes = 0; - - R_ResetViewRendering2D(); - - R_Bloom_CopyHDRTexture(); - R_Bloom_MakeTexture(); - - // restore the view settings - r_waterstate.enabled = oldwaterstate; - r_refdef.view.width = oldwidth; - r_refdef.view.height = oldheight; - r_refdef.view.colorscale = oldcolorscale; - - R_ResetViewRendering3D(); - - R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("viewclear"); -} - -static void R_BlendView(void) +static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) { unsigned int permutation; float uservecs[4][4]; + R_EntityMatrix(&identitymatrix); + switch (vid.renderpath) { case RENDERPATH_GL20: @@ -6417,21 +6708,21 @@ static void R_BlendView(void) case RENDERPATH_SOFT: case RENDERPATH_GLES2: permutation = - (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0) + (r_fb.bloomtexture[r_fb.bloomindex] ? SHADERPERMUTATION_BLOOM : 0) | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0) | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0) | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0) | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0); - if (r_bloomstate.texture_screen) + if (r_fb.colortexture) { - // make sure the buffer is available - if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); } - - R_ResetViewRendering2D(); - R_Mesh_SetMainRenderTargets(); + if (!r_fb.fbo) + { + R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + } - if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0)) + if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture) { // declare variables float blur_factor, blur_mouseaccel, blur_velocity; @@ -6449,10 +6740,10 @@ static void R_BlendView(void) // from the goal, pick an averaged value between goal and last value cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1); blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha; - + // enforce minimum amount of blur blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value; - + //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel); // calculate values into a standard alpha @@ -6465,13 +6756,14 @@ static void R_BlendView(void) / max(0.0001, cl.time - cl.oldtime) // fps independent ); - + // randomization for the blur value to combat persistent ghosting cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value); cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value); - + // apply the blur - if (cl.motionbluralpha > 0 && !r_refdef.envmap) + R_ResetViewRendering2D(fbo, depthtexture, colortexture); + if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid) { GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Color(1, 1, 1, cl.motionbluralpha); @@ -6483,48 +6775,47 @@ static void R_BlendView(void) case RENDERPATH_GLES1: case RENDERPATH_GLES2: case RENDERPATH_SOFT: - R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.screentexcoord2f); break; case RENDERPATH_D3D9: case RENDERPATH_D3D10: case RENDERPATH_D3D11: - R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_bloomstate.screentexcoord2f); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f); break; } - R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1, false, true); + R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); - r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; } - - // updates old view angles for next pass + + // updates old view angles for next pass VectorCopy(cl.viewangles, blur_oldangles); - } - // copy view into the screen texture - R_Mesh_CopyToTexture(r_bloomstate.texture_screen, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); - r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + // copy view into the ghost texture + R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + r_fb.ghosttexture_valid = true; + } } - else if (!r_bloomstate.texture_bloom) + else { + // no r_fb.colortexture means we're rendering to the real fb // we may still have to do view tint... if (r_refdef.viewblend[3] >= (1.0f / 256.0f)) { // apply a color tint to the whole view - R_ResetViewRendering2D(); + R_ResetViewRendering2D(0, NULL, NULL); GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, true); + R_SetupShader_Generic_NoTexture(false, true); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } break; // no screen processing, no bloom, skip it } - if (r_bloomstate.texture_bloom && !r_bloomstate.hdr) + if (r_fb.bloomtexture[0]) { - // render simple bloom effect - // copy the screen and shrink it and darken it for the bloom process - R_Bloom_CopyBloomTexture(r_bloom_colorscale.value); // make the bloom texture R_Bloom_MakeTexture(); } @@ -6542,7 +6833,7 @@ static void R_BlendView(void) if (r_glsl_postprocess_uservec4_enable.integer) sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]); - R_ResetViewRendering2D(); + R_ResetViewRendering2D(0, NULL, NULL); // here we render to the real framebuffer! GL_Color(1, 1, 1, 1); GL_BlendFunc(GL_ONE, GL_ZERO); @@ -6550,13 +6841,13 @@ static void R_BlendView(void) { case RENDERPATH_GL20: case RENDERPATH_GLES2: - R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f); + R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f); R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation); - if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_bloomstate.texture_screen); - if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_bloomstate.texture_bloom ); + if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_fb.colortexture); + if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_fb.bloomtexture[r_fb.bloomindex]); if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps ); 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]); - if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight); + if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight); 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]); 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]); 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]); @@ -6568,13 +6859,13 @@ static void R_BlendView(void) case RENDERPATH_D3D9: #ifdef SUPPORTD3D // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that... - R_Mesh_PrepareVertices_Mesh_Arrays(4, r_d3dscreenvertex3f, NULL, NULL, NULL, NULL, r_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f); + R_Mesh_PrepareVertices_Mesh_Arrays(4, r_d3dscreenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f); R_SetupShader_SetPermutationHLSL(SHADERMODE_POSTPROCESS, permutation); - R_Mesh_TexBind(GL20TU_FIRST , r_bloomstate.texture_screen); - R_Mesh_TexBind(GL20TU_SECOND , r_bloomstate.texture_bloom ); + R_Mesh_TexBind(GL20TU_FIRST , r_fb.colortexture); + R_Mesh_TexBind(GL20TU_SECOND , r_fb.bloomtexture[r_fb.bloomindex]); R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps ); hlslPSSetParameter4f(D3DPSREGISTER_ViewTintColor , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); - hlslPSSetParameter2f(D3DPSREGISTER_PixelSize , 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight); + hlslPSSetParameter2f(D3DPSREGISTER_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight); hlslPSSetParameter4f(D3DPSREGISTER_UserVec1 , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]); hlslPSSetParameter4f(D3DPSREGISTER_UserVec2 , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]); hlslPSSetParameter4f(D3DPSREGISTER_UserVec3 , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]); @@ -6591,13 +6882,13 @@ static void R_BlendView(void) Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); break; case RENDERPATH_SOFT: - R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f); + R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f); R_SetupShader_SetPermutationSoft(SHADERMODE_POSTPROCESS, permutation); - R_Mesh_TexBind(GL20TU_FIRST , r_bloomstate.texture_screen); - R_Mesh_TexBind(GL20TU_SECOND , r_bloomstate.texture_bloom ); + R_Mesh_TexBind(GL20TU_FIRST , r_fb.colortexture); + R_Mesh_TexBind(GL20TU_SECOND , r_fb.bloomtexture[r_fb.bloomindex]); R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps ); DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ViewTintColor , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); - DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelSize , 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight); + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight); DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_UserVec1 , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]); DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_UserVec2 , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]); DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_UserVec3 , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]); @@ -6610,7 +6901,7 @@ static void R_BlendView(void) break; } R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); - r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height; + r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height; break; case RENDERPATH_GL11: case RENDERPATH_GL13: @@ -6618,10 +6909,10 @@ static void R_BlendView(void) if (r_refdef.viewblend[3] >= (1.0f / 256.0f)) { // apply a color tint to the whole view - R_ResetViewRendering2D(); + R_ResetViewRendering2D(0, NULL, NULL); GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, true); + R_SetupShader_Generic_NoTexture(false, true); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } @@ -6631,7 +6922,7 @@ static void R_BlendView(void) matrix4x4_t r_waterscrollmatrix; -void R_UpdateFog(void) // needs to be called before HDR subrender too, as that changes colorscale! +void R_UpdateFog(void) { // Nehahra fog if (gamemode == GAME_NEHAHRA) @@ -6745,6 +7036,10 @@ void R_UpdateVariables(void) { r_refdef.lightmapintensity *= r_fakelight_intensity.value; } + else if (r_refdef.scene.worldmodel) + { + r_refdef.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale; + } if (r_showsurfaces.integer) { r_refdef.scene.rtworld = false; @@ -6754,9 +7049,11 @@ void R_UpdateVariables(void) r_refdef.lightmapintensity = 0; } + r_gpuskeletal = false; switch(vid.renderpath) { case RENDERPATH_GL20: + r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal! case RENDERPATH_D3D9: case RENDERPATH_D3D10: case RENDERPATH_D3D11: @@ -6836,7 +7133,7 @@ r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype ) } } -int R_SortEntities_Compare(const void *ap, const void *bp) +static int R_SortEntities_Compare(const void *ap, const void *bp) { const entity_render_t *a = *(const entity_render_t **)ap; const entity_render_t *b = *(const entity_render_t **)bp; @@ -6858,7 +7155,7 @@ int R_SortEntities_Compare(const void *ap, const void *bp) // everything we compared is equal return 0; } -void R_SortEntities(void) +static void R_SortEntities(void) { // below or equal 2 ents, sorting never gains anything if(r_refdef.scene.numentities <= 2) @@ -6873,11 +7170,13 @@ R_RenderView ================ */ int dpsoftrast_test; -extern void R_Shadow_UpdateBounceGridTexture(void); extern cvar_t r_shadow_bouncegrid; void R_RenderView(void) { matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix; + int fbo; + rtexture_t *depthtexture; + rtexture_t *colortexture; dpsoftrast_test = r_test.integer; @@ -6895,7 +7194,6 @@ void R_RenderView(void) R_SortEntities(); R_AnimCache_ClearCache(); - R_FrameData_NewFrame(); /* adjust for stereo display */ if(R_Stereo_Active()) @@ -6907,15 +7205,16 @@ void R_RenderView(void) if (r_refdef.view.isoverlay) { // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas] + R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL); GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0); R_TimeReport("depthclear"); r_refdef.view.showdebug = false; - r_waterstate.enabled = false; - r_waterstate.numwaterplanes = 0; + r_fb.water.enabled = false; + r_fb.water.numwaterplanes = 0; - R_RenderScene(); + R_RenderScene(0, NULL, NULL); r_refdef.view.matrix = originalmatrix; @@ -6926,25 +7225,40 @@ void R_RenderView(void) if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/) { r_refdef.view.matrix = originalmatrix; - return; //Host_Error ("R_RenderView: NULL worldmodel"); + return; } r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value; + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + // in sRGB fallback, behave similar to true sRGB: convert this + // value from linear to sRGB + r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale); + R_RenderView_UpdateViewVectors(); R_Shadow_UpdateWorldLightSelection(); R_Bloom_StartFrame(); + + // apply bloom brightness offset + if(r_fb.bloomtexture[0]) + r_refdef.view.colorscale *= r_bloom_scenebrightness.value; + R_Water_StartFrame(); + // now we probably have an fbo to render into + fbo = r_fb.fbo; + depthtexture = r_fb.depthtexture; + colortexture = r_fb.colortexture; + CHECKGLERROR if (r_timereport_active) R_TimeReport("viewsetup"); - R_ResetViewRendering3D(); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); - if (r_refdef.view.clear || r_refdef.fogenabled) + if (r_refdef.view.clear || r_refdef.fogenabled || fbo) { R_ClearScreen(r_refdef.fogenabled); if (r_timereport_active) @@ -6952,32 +7266,28 @@ void R_RenderView(void) } r_refdef.view.clear = true; - // this produces a bloom texture to be used in R_BlendView() later - if (r_bloomstate.hdr) - { - R_HDR_RenderBloomTexture(); - // we have to bump the texture frame again because r_refdef.view.colorscale is cached in the textures - r_textureframe++; // used only by R_GetCurrentTexture - } - r_refdef.view.showdebug = true; R_View_Update(); if (r_timereport_active) R_TimeReport("visibility"); + R_AnimCache_CacheVisibleEntities(); + if (r_timereport_active) + R_TimeReport("animcache"); + R_Shadow_UpdateBounceGridTexture(); if (r_timereport_active && r_shadow_bouncegrid.integer) R_TimeReport("bouncegrid"); - r_waterstate.numwaterplanes = 0; - if (r_waterstate.enabled) - R_RenderWaterPlanes(); + r_fb.water.numwaterplanes = 0; + if (r_fb.water.enabled) + R_RenderWaterPlanes(fbo, depthtexture, colortexture); - R_RenderScene(); - r_waterstate.numwaterplanes = 0; + R_RenderScene(fbo, depthtexture, colortexture); + r_fb.water.numwaterplanes = 0; - R_BlendView(); + R_BlendView(fbo, depthtexture, colortexture); if (r_timereport_active) R_TimeReport("blendview"); @@ -6989,7 +7299,7 @@ void R_RenderView(void) CHECKGLERROR } -void R_RenderWaterPlanes(void) +void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) { if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) { @@ -7006,33 +7316,28 @@ void R_RenderWaterPlanes(void) if (r_timereport_active) R_TimeReport("watermodels"); - if (r_waterstate.numwaterplanes) + if (r_fb.water.numwaterplanes) { - R_Water_ProcessPlanes(); + R_Water_ProcessPlanes(fbo, depthtexture, colortexture); if (r_timereport_active) R_TimeReport("waterscenes"); } } -extern void R_DrawLightningBeams (void); -extern void VM_CL_AddPolygonsToMeshQueue (void); -extern void R_DrawPortals (void); extern cvar_t cl_locs_show; static void R_DrawLocs(void); static void R_DrawEntityBBoxes(void); static void R_DrawModelDecals(void); -extern void R_DrawModelShadows(void); -extern void R_DrawModelShadowMaps(void); extern cvar_t cl_decals_newsystem; extern qboolean r_shadow_usingdeferredprepass; -void R_RenderScene(void) +void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) { qboolean shadowmapping = false; if (r_timereport_active) R_TimeReport("beginscene"); - r_refdef.stats.renders++; + r_refdef.stats[r_stat_renders]++; R_UpdateFog(); @@ -7068,15 +7373,15 @@ void R_RenderScene(void) if (skyrendermasked && skyrenderlater) { // we have to force off the water clipping plane while rendering sky - R_SetupView(false); + R_SetupView(false, fbo, depthtexture, colortexture); R_Sky(); - R_SetupView(true); + R_SetupView(true, fbo, depthtexture, colortexture); if (r_timereport_active) R_TimeReport("sky"); } } - R_Shadow_PrepareLights(); + R_Shadow_PrepareLights(fbo, depthtexture, colortexture); if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0) R_Shadow_PrepareModelShadows(); if (r_timereport_active) @@ -7103,8 +7408,9 @@ void R_RenderScene(void) if (r_shadows.integer >= 2 && shadowmapping && r_refdef.lightmapintensity > 0) { - R_DrawModelShadowMaps(); - R_ResetViewRendering3D(); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + R_DrawModelShadowMaps(fbo, depthtexture, colortexture); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); // don't let sound skip if going slow if (r_refdef.scene.extraupdate) S_ExtraUpdate (); @@ -7131,8 +7437,9 @@ void R_RenderScene(void) if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0) { - R_DrawModelShadows(); - R_ResetViewRendering3D(); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + R_DrawModelShadows(fbo, depthtexture, colortexture); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); // don't let sound skip if going slow if (r_refdef.scene.extraupdate) S_ExtraUpdate (); @@ -7151,8 +7458,9 @@ void R_RenderScene(void) if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0) { - R_DrawModelShadows(); - R_ResetViewRendering3D(); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + R_DrawModelShadows(fbo, depthtexture, colortexture); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); // don't let sound skip if going slow if (r_refdef.scene.extraupdate) S_ExtraUpdate (); @@ -7186,7 +7494,8 @@ void R_RenderScene(void) R_TimeReport("lightning"); } - VM_CL_AddPolygonsToMeshQueue(); + if (cl.csqc_loaded) + VM_CL_AddPolygonsToMeshQueue(CLVM_prog); if (r_refdef.view.showdebug) { @@ -7260,8 +7569,6 @@ void R_RenderScene(void) // don't let sound skip if going slow if (r_refdef.scene.extraupdate) S_ExtraUpdate (); - - R_ResetViewRendering2D(); } static const unsigned short bboxelements[36] = @@ -7274,7 +7581,7 @@ static const unsigned short bboxelements[36] = 1, 0, 2, 1, 2, 3, }; -void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca) +static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca) { int i; float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4]; @@ -7309,26 +7616,24 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa } R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL); R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0); } static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { + prvm_prog_t *prog = SVVM_prog; int i; float color[4]; prvm_edict_t *edict; - prvm_prog_t *prog_save = prog; // this function draws bounding boxes of server entities if (!sv.active) return; GL_CullFace(GL_NONE); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); - prog = 0; - SV_VM_Begin(); for (i = 0;i < numsurfaces;i++) { edict = PRVM_EDICT_NUM(surfacelist[i]); @@ -7339,6 +7644,7 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break; case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break; case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break; + case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break; default: Vector4Set(color, 0, 0, 0, 0.50);break; } color[3] *= r_showbboxes.value; @@ -7347,8 +7653,6 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh GL_CullFace(r_refdef.view.cullface_front); R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]); } - SV_VM_End(); - prog = prog_save; } static void R_DrawEntityBBoxes(void) @@ -7356,14 +7660,12 @@ static void R_DrawEntityBBoxes(void) int i; prvm_edict_t *edict; vec3_t center; - prvm_prog_t *prog_save = prog; + prvm_prog_t *prog = SVVM_prog; // this function draws bounding boxes of server entities if (!sv.active) return; - prog = 0; - SV_VM_Begin(); for (i = 0;i < prog->num_edicts;i++) { edict = PRVM_EDICT_NUM(i); @@ -7375,10 +7677,8 @@ static void R_DrawEntityBBoxes(void) if(PRVM_serveredictedict(edict, viewmodelforclient) != 0) continue; VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center); - R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL); } - SV_VM_End(); - prog = prog_save; } static const int nomodelelement3i[24] = @@ -7425,7 +7725,7 @@ static const float nomodelcolor4f[6*4] = 0.5f, 0.0f, 0.0f, 1.0f }; -void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { int i; float f1, f2, *c; @@ -7475,7 +7775,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight } } // R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL); R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0); } @@ -7485,12 +7785,12 @@ void R_DrawNoModel(entity_render_t *ent) vec3_t org; Matrix4x4_OriginFromMatrix(&ent->matrix, org); if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1)) - R_MeshQueue_AddTransparent(ent->flags & RENDER_NODEPTHTEST ? r_refdef.view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight); + R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight); else R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL); } -void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width) +void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width) { vec3_t right1, right2, diff, normal; @@ -7536,7 +7836,7 @@ void R_CalcSprite_Vertex3f(float *vertex3f, const vec3_t origin, const vec3_t le vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1; } -int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z) +static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z) { int i; float *vertex3f; @@ -7579,7 +7879,7 @@ void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f) } } -void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d) +static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d) { int i; int *e, element[3]; @@ -7698,13 +7998,24 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms) return (float) f; } -void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags) +static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags) { int w, h, idx; - double f; - double offsetd[2]; + float shadertime; + float f; float tcmat[12]; matrix4x4_t matrix, temp; + // if shadertime exceeds about 9 hours (32768 seconds), just wrap it, + // it's better to have one huge fixup every 9 hours than gradual + // degradation over time which looks consistently bad after many hours. + // + // tcmod scroll in particular suffers from this degradation which can't be + // effectively worked around even with floor() tricks because we don't + // know if tcmod scroll is the last tcmod being applied, and for clampmap + // a workaround involving floor() would be incorrect anyway... + shadertime = rsurface.shadertime; + if (shadertime >= 32768.0f) + shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f; switch(tcmod->tcmod) { case Q3TCMOD_COUNT: @@ -7720,19 +8031,18 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t Matrix4x4_CreateTranslate(&matrix, 0, 0, 0); break; case Q3TCMOD_ROTATE: - f = tcmod->parms[0] * rsurface.shadertime; Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0); - Matrix4x4_ConcatRotate(&matrix, (f / 360 - floor(f / 360)) * 360, 0, 0, 1); + Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1); Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0); break; case Q3TCMOD_SCALE: Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1); break; case Q3TCMOD_SCROLL: - // extra care is needed because of precision breakdown with large values of time - offsetd[0] = tcmod->parms[0] * rsurface.shadertime; - offsetd[1] = tcmod->parms[1] * rsurface.shadertime; - Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0); + // this particular tcmod is the most prone to precision breakdown + // at large values, but as we wrap shadertime it won't be obvious + // in practice. + Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * rsurface.shadertime, tcmod->parms[1] * rsurface.shadertime, 0); break; case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures) w = (int) tcmod->parms[0]; @@ -7762,7 +8072,7 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t Matrix4x4_Concat(texmatrix, &matrix, &temp); } -void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname) +static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname) { int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP; char name[MAX_QPATH]; @@ -7793,15 +8103,15 @@ texture_t *R_GetCurrentTexture(texture_t *t) { int i; const entity_render_t *ent = rsurface.entity; - dp_model_t *model = ent->model; + dp_model_t *model = ent->model; // when calling this, ent must not be NULL q3shaderinfo_layer_tcmod_t *tcmod; - if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent) + if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate) return t->currentframe; t->update_lastrenderframe = r_textureframe; t->update_lastrenderentity = (void *)ent; - if(ent && ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS) + if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS) t->camera_entity = ent->entitynumber; else t->camera_entity = 0; @@ -7859,9 +8169,9 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->currentalpha = rsurface.colormod[3]; if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer)) t->currentalpha *= r_wateralpha.value; - if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay) + if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later - if(!r_waterstate.enabled || r_refdef.view.isoverlay) + if(!r_fb.water.enabled || r_refdef.view.isoverlay) t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA); if (!(rsurface.ent_flags & RENDER_LIGHT)) t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT; @@ -7869,7 +8179,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) { // no modellight if using fakelight for the map } - else if (rsurface.modeltexcoordlightmap2f == NULL && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + else if ((rsurface.modeltexcoordlightmap2f == NULL || (rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT))) && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) { // pick a model lighting mode if (VectorLength2(rsurface.modellight_diffuse) >= (1.0f / 256.0f)) @@ -7945,6 +8255,11 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->backgroundglowtexture = t->backgroundcurrentskinframe->glow; if (!t->backgroundnmaptexture) t->backgroundnmaptexture = r_texture_blanknormalmap; + // make sure that if glow is going to be used, both textures are not NULL + if (!t->backgroundglowtexture && t->glowtexture) + t->backgroundglowtexture = r_texture_black; + if (!t->glowtexture && t->backgroundglowtexture) + t->glowtexture = r_texture_black; } else { @@ -7987,13 +8302,15 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->basetexture = r_texture_grey128; t->pantstexture = r_texture_black; t->shirttexture = r_texture_black; - t->nmaptexture = r_texture_blanknormalmap; + if (gl_lightmaps.integer < 2) + t->nmaptexture = r_texture_blanknormalmap; t->glosstexture = r_texture_black; t->glowtexture = NULL; t->fogtexture = NULL; t->reflectmasktexture = NULL; t->backgroundbasetexture = NULL; - t->backgroundnmaptexture = r_texture_blanknormalmap; + if (gl_lightmaps.integer < 2) + t->backgroundnmaptexture = r_texture_blanknormalmap; t->backgroundglosstexture = r_texture_black; t->backgroundglowtexture = NULL; t->specularscale = 0; @@ -8028,7 +8345,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) blendfunc2 = GL_ZERO; } // don't colormod evilblend textures - if(!R_BlendFuncFlags(blendfunc1, blendfunc2) & BLENDFUNC_ALLOWS_COLORMOD) + if(!(R_BlendFuncFlags(blendfunc1, blendfunc2) & BLENDFUNC_ALLOWS_COLORMOD)) VectorSet(t->lightmapcolor, 1, 1, 1); depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED); if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) @@ -8133,6 +8450,11 @@ void RSurf_ActiveWorldEntity(void) rsurface.ent_alttextures = false; rsurface.basepolygonfactor = r_refdef.polygonfactor; rsurface.basepolygonoffset = r_refdef.polygonoffset; + rsurface.entityskeletaltransform3x4 = NULL; + rsurface.entityskeletaltransform3x4buffer = NULL; + rsurface.entityskeletaltransform3x4offset = 0; + rsurface.entityskeletaltransform3x4size = 0;; + rsurface.entityskeletalnumtransforms = 0; rsurface.modelvertex3f = model->surfmesh.data_vertex3f; rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f; @@ -8154,6 +8476,12 @@ void RSurf_ActiveWorldEntity(void) rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f; rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f; + rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub; + rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub; + rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub; + rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub; rsurface.modelelement3i = model->surfmesh.data_element3i; rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer; rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset; @@ -8164,9 +8492,9 @@ void RSurf_ActiveWorldEntity(void) rsurface.modelnumvertices = model->surfmesh.num_vertices; rsurface.modelnumtriangles = model->surfmesh.num_triangles; rsurface.modelsurfaces = model->data_surfaces; - rsurface.modelvertexmesh = model->surfmesh.vertexmesh; - rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer; - rsurface.modelvertex3fbuffer = model->surfmesh.vertex3fbuffer; + rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh; + rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f; rsurface.modelgeneratedvertex = false; rsurface.batchgeneratedvertex = false; rsurface.batchfirstvertex = 0; @@ -8194,9 +8522,15 @@ void RSurf_ActiveWorldEntity(void) rsurface.batchtexcoordlightmap2f = NULL; rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; rsurface.batchvertexmesh = NULL; - rsurface.batchvertexmeshbuffer = NULL; - rsurface.batchvertex3fbuffer = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; rsurface.batchelement3i = NULL; rsurface.batchelement3i_indexbuffer = NULL; rsurface.batchelement3i_bufferoffset = 0; @@ -8206,6 +8540,7 @@ void RSurf_ActiveWorldEntity(void) rsurface.passcolor4f = NULL; rsurface.passcolor4f_vertexbuffer = NULL; rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = false; } void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass) @@ -8248,63 +8583,129 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value; rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value; } - if (model->surfmesh.isanimated && model->AnimateVertices) + // if the animcache code decided it should use the shader path, skip the deform step + rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4; + rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer; + rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset; + rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size; + rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0; + if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4) { if (ent->animcache_vertex3f) { + r_refdef.stats[r_stat_batch_entitycache_count]++; + r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles; rsurface.modelvertex3f = ent->animcache_vertex3f; + rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer; + rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset; rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL; + rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL; + rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0; rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL; + rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL; + rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0; rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL; + rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL; + rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0; rsurface.modelvertexmesh = ent->animcache_vertexmesh; - rsurface.modelvertexmeshbuffer = ent->animcache_vertexmeshbuffer; - rsurface.modelvertex3fbuffer = ent->animcache_vertex3fbuffer; + rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer; + rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset; } else if (wanttangents) { + r_refdef.stats[r_stat_batch_entityanimate_count]++; + r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles; rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f); rsurface.modelvertexmesh = NULL; - rsurface.modelvertexmeshbuffer = NULL; - rsurface.modelvertex3fbuffer = NULL; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = NULL; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = 0; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelsvector3f_vertexbuffer = 0; + rsurface.modelsvector3f_bufferoffset = 0; + rsurface.modeltvector3f_vertexbuffer = 0; + rsurface.modeltvector3f_bufferoffset = 0; + rsurface.modelnormal3f_vertexbuffer = 0; + rsurface.modelnormal3f_bufferoffset = 0; } else if (wantnormals) { + r_refdef.stats[r_stat_batch_entityanimate_count]++; + r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles; rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); rsurface.modelsvector3f = NULL; rsurface.modeltvector3f = NULL; rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL); rsurface.modelvertexmesh = NULL; - rsurface.modelvertexmeshbuffer = NULL; - rsurface.modelvertex3fbuffer = NULL; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = NULL; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = 0; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelsvector3f_vertexbuffer = 0; + rsurface.modelsvector3f_bufferoffset = 0; + rsurface.modeltvector3f_vertexbuffer = 0; + rsurface.modeltvector3f_bufferoffset = 0; + rsurface.modelnormal3f_vertexbuffer = 0; + rsurface.modelnormal3f_bufferoffset = 0; } else { + r_refdef.stats[r_stat_batch_entityanimate_count]++; + r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles; rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); rsurface.modelsvector3f = NULL; rsurface.modeltvector3f = NULL; rsurface.modelnormal3f = NULL; model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL); rsurface.modelvertexmesh = NULL; - rsurface.modelvertexmeshbuffer = NULL; - rsurface.modelvertex3fbuffer = NULL; - } - rsurface.modelvertex3f_vertexbuffer = 0; - rsurface.modelvertex3f_bufferoffset = 0; - rsurface.modelsvector3f_vertexbuffer = 0; - rsurface.modelsvector3f_bufferoffset = 0; - rsurface.modeltvector3f_vertexbuffer = 0; - rsurface.modeltvector3f_bufferoffset = 0; - rsurface.modelnormal3f_vertexbuffer = 0; - rsurface.modelnormal3f_bufferoffset = 0; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = NULL; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = 0; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelsvector3f_vertexbuffer = 0; + rsurface.modelsvector3f_bufferoffset = 0; + rsurface.modeltvector3f_vertexbuffer = 0; + rsurface.modeltvector3f_bufferoffset = 0; + rsurface.modelnormal3f_vertexbuffer = 0; + rsurface.modelnormal3f_bufferoffset = 0; + } rsurface.modelgeneratedvertex = true; } else { + if (rsurface.entityskeletaltransform3x4) + { + r_refdef.stats[r_stat_batch_entityskeletal_count]++; + r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles; + } + else + { + r_refdef.stats[r_stat_batch_entitystatic_count]++; + r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles; + } rsurface.modelvertex3f = model->surfmesh.data_vertex3f; rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f; @@ -8317,9 +8718,9 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.modelnormal3f = model->surfmesh.data_normal3f; rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f; - rsurface.modelvertexmesh = model->surfmesh.vertexmesh; - rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer; - rsurface.modelvertex3fbuffer = model->surfmesh.vertex3fbuffer; + rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh; + rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f; rsurface.modelgeneratedvertex = false; } rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f; @@ -8331,6 +8732,12 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f; rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f; + rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub; + rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub; + rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub; + rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub; rsurface.modelelement3i = model->surfmesh.data_element3i; rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer; rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset; @@ -8367,9 +8774,15 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.batchtexcoordlightmap2f = NULL; rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; rsurface.batchvertexmesh = NULL; - rsurface.batchvertexmeshbuffer = NULL; - rsurface.batchvertex3fbuffer = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; rsurface.batchelement3i = NULL; rsurface.batchelement3i_indexbuffer = NULL; rsurface.batchelement3i_bufferoffset = 0; @@ -8379,6 +8792,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.passcolor4f = NULL; rsurface.passcolor4f_vertexbuffer = NULL; rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = false; } void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents) @@ -8414,6 +8828,15 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve rsurface.ent_alttextures = false; rsurface.basepolygonfactor = r_refdef.polygonfactor; rsurface.basepolygonoffset = r_refdef.polygonoffset; + rsurface.entityskeletaltransform3x4 = NULL; + rsurface.entityskeletaltransform3x4buffer = NULL; + rsurface.entityskeletaltransform3x4offset = 0; + rsurface.entityskeletaltransform3x4size = 0; + rsurface.entityskeletalnumtransforms = 0; + r_refdef.stats[r_stat_batch_entitycustom_count]++; + r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1; + r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices; + r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles; if (wanttangents) { rsurface.modelvertex3f = (float *)vertex3f; @@ -8436,8 +8859,8 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve rsurface.modelnormal3f = NULL; } rsurface.modelvertexmesh = NULL; - rsurface.modelvertexmeshbuffer = NULL; - rsurface.modelvertex3fbuffer = NULL; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; rsurface.modelvertex3f_vertexbuffer = 0; rsurface.modelvertex3f_bufferoffset = 0; rsurface.modelsvector3f_vertexbuffer = 0; @@ -8456,6 +8879,12 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve rsurface.modeltexcoordlightmap2f = NULL; rsurface.modeltexcoordlightmap2f_vertexbuffer = 0; rsurface.modeltexcoordlightmap2f_bufferoffset = 0; + rsurface.modelskeletalindex4ub = NULL; + rsurface.modelskeletalindex4ub_vertexbuffer = NULL; + rsurface.modelskeletalindex4ub_bufferoffset = 0; + rsurface.modelskeletalweight4ub = NULL; + rsurface.modelskeletalweight4ub_vertexbuffer = NULL; + rsurface.modelskeletalweight4ub_bufferoffset = 0; rsurface.modelelement3i = (int *)element3i; rsurface.modelelement3i_indexbuffer = NULL; rsurface.modelelement3i_bufferoffset = 0; @@ -8490,9 +8919,15 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve rsurface.batchtexcoordlightmap2f = NULL; rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; rsurface.batchvertexmesh = NULL; - rsurface.batchvertexmeshbuffer = NULL; - rsurface.batchvertex3fbuffer = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; rsurface.batchelement3i = NULL; rsurface.batchelement3i_indexbuffer = NULL; rsurface.batchelement3i_bufferoffset = 0; @@ -8502,6 +8937,7 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve rsurface.passcolor4f = NULL; rsurface.passcolor4f_vertexbuffer = NULL; rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = true; if (rsurface.modelnumvertices && rsurface.modelelement3i) { @@ -8551,7 +8987,7 @@ float RSurf_FogVertex(const float *v) return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)]; } -void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust) +static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust) { int i; for (i = 0;i < numelements;i++) @@ -8573,6 +9009,7 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const int surfacefirstvertex; int surfaceendvertex; int surfacenumvertices; + int batchnumsurfaces = texturenumsurfaces; int batchnumvertices; int batchnumtriangles; int needsupdate; @@ -8584,6 +9021,7 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const float scale; float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3]; float waveparms[4]; + unsigned char *ub; q3shaderinfo_deform_t *deform; const msurface_t *surface, *firstsurface; r_vertexmesh_t *vertexmesh; @@ -8613,6 +9051,13 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const batchnumtriangles += surfacenumtriangles; } + r_refdef.stats[r_stat_batch_batches]++; + if (gaps) + r_refdef.stats[r_stat_batch_withgaps]++; + r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles; + // we now know the vertex range used, and if there are any gaps in it rsurface.batchfirstvertex = firstvertex; rsurface.batchnumvertices = endvertex - firstvertex; @@ -8626,11 +9071,30 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const // check if any dynamic vertex processing must occur dynamicvertex = false; + // a cvar to force the dynamic vertex path to be taken, for debugging + if (r_batch_debugdynamicvertexpath.integer) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles; + } + dynamicvertex = true; + } + // if there is a chance of animated vertex colors, it's a dynamic batch if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo) { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_NOGAPS; needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR; } @@ -8651,37 +9115,79 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const case Q3DEFORM_NONE: break; case Q3DEFORM_AUTOSPRITE: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD; needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; break; case Q3DEFORM_AUTOSPRITE2: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD; needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; break; case Q3DEFORM_NORMAL: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD; needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; break; case Q3DEFORM_WAVE: if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms)) break; // if wavefunc is a nop, ignore this transform + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD; needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; break; case Q3DEFORM_BULGE: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD; needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; break; case Q3DEFORM_MOVE: if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms)) break; // if wavefunc is a nop, ignore this transform + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX; needsupdate |= BATCHNEED_VERTEXMESH_VERTEX; break; } @@ -8692,36 +9198,90 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const case Q3TCGEN_TEXTURE: break; case Q3TCGEN_LIGHTMAP: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_LIGHTMAP | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_LIGHTMAP; needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP; break; case Q3TCGEN_VECTOR: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX; needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; break; case Q3TCGEN_ENVIRONMENT: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL; needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; break; } if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT) { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD; needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; } if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))) { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles; + } dynamicvertex = true; - batchneed |= BATCHNEED_NOGAPS; needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)); } - if (dynamicvertex || gaps || rsurface.batchfirstvertex) + // when the model data has no vertex buffer (dynamic mesh), we need to + // eliminate gaps + if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer) + batchneed |= BATCHNEED_NOGAPS; + + // the caller can specify BATCHNEED_NOGAPS to force a batch with + // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex), + // we ensure this by treating the vertex batch as dynamic... + if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles; + } + dynamicvertex = true; + } + + if (dynamicvertex) { // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set... if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX; @@ -8730,25 +9290,38 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR; if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD; if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP; + if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL) batchneed |= BATCHNEED_ARRAY_SKELETAL; } - // when the model data has no vertex buffer (dynamic mesh), we need to - // eliminate gaps - if (vid.useinterleavedarrays ? !rsurface.modelvertexmeshbuffer : !rsurface.modelvertex3f_vertexbuffer) - batchneed |= BATCHNEED_NOGAPS; - // if needsupdate, we have to do a dynamic vertex batch for sure if (needsupdate & batchneed) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles; + } dynamicvertex = true; + } // see if we need to build vertexmesh from arrays if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles; + } dynamicvertex = true; + } - // if gaps are unacceptable, and there are gaps, it's a dynamic batch... - // also some drivers strongly dislike firstvertex - if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex)) - dynamicvertex = true; + // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data + if (dynamicvertex && rsurface.entityskeletaltransform3x4) + batchneed |= BATCHNEED_ARRAY_SKELETAL; rsurface.batchvertex3f = rsurface.modelvertex3f; rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer; @@ -8771,15 +9344,26 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f; rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer; rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset; - rsurface.batchvertex3fbuffer = rsurface.modelvertex3fbuffer; + rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub; + rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer; + rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset; + rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub; + rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer; + rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset; rsurface.batchvertexmesh = rsurface.modelvertexmesh; - rsurface.batchvertexmeshbuffer = rsurface.modelvertexmeshbuffer; + rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer; + rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset; rsurface.batchelement3i = rsurface.modelelement3i; rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer; rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset; rsurface.batchelement3s = rsurface.modelelement3s; rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer; rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset; + rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4; + rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer; + rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset; + rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size; + rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms; // if any dynamic vertex processing has to occur in software, we copy the // entire surface list together before processing to rebase the vertices @@ -8789,10 +9373,15 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const // copy the surface list together to avoid wasting upload bandwidth on the // vertices in the gaps. // - // if gaps exist and we have a static vertex buffer, we still have to - // combine the index buffer ranges into one dynamic index buffer. + // if gaps exist and we have a static vertex buffer, we can choose whether + // to combine the index buffer ranges into one dynamic index buffer or + // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW). // - // in all cases we end up with data that can be drawn in one call. + // in many cases the batch is reduced to one draw call. + + rsurface.batchmultidraw = false; + rsurface.batchmultidrawnumsurfaces = 0; + rsurface.batchmultidrawsurfacelist = NULL; if (!dynamicvertex) { @@ -8802,6 +9391,17 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const // otherwise use the original static buffer with an appropriate offset if (gaps) { + r_refdef.stats[r_stat_batch_copytriangles_batches] += 1; + r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles; + if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer) + { + rsurface.batchmultidraw = true; + rsurface.batchmultidrawnumsurfaces = texturenumsurfaces; + rsurface.batchmultidrawsurfacelist = texturesurfacelist; + return; + } // build a new triangle elements array for this batch rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3])); rsurface.batchfirsttriangle = 0; @@ -8825,6 +9425,21 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const for (i = 0;i < numtriangles*3;i++) rsurface.batchelement3s[i] = rsurface.batchelement3i[i]; } + // upload buffer data for the copytriangles batch + if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo) + { + if (rsurface.batchelement3s) + rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset); + else if (rsurface.batchelement3i) + rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset); + } + } + else + { + r_refdef.stats[r_stat_batch_fast_batches] += 1; + r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles; } return; } @@ -8833,14 +9448,21 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const // we only directly handle separate array data in this case and then // generate interleaved data if needed... rsurface.batchgeneratedvertex = true; + r_refdef.stats[r_stat_batch_dynamic_batches] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles; // now copy the vertex data into a combined array and make an index array // (this is what Quake3 does all the time) - //if (gaps || rsurface.batchfirstvertex) + // we also apply any skeletal animation here that would have been done in + // the vertex shader, because most of the dynamic vertex animation cases + // need actual vertex positions and normals + //if (dynamicvertex) { - rsurface.batchvertex3fbuffer = NULL; rsurface.batchvertexmesh = NULL; - rsurface.batchvertexmeshbuffer = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; rsurface.batchvertex3f = NULL; rsurface.batchvertex3f_vertexbuffer = NULL; rsurface.batchvertex3f_bufferoffset = 0; @@ -8862,12 +9484,21 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const rsurface.batchtexcoordlightmap2f = NULL; rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3])); rsurface.batchelement3i_indexbuffer = NULL; rsurface.batchelement3i_bufferoffset = 0; rsurface.batchelement3s = NULL; rsurface.batchelement3s_indexbuffer = NULL; rsurface.batchelement3s_bufferoffset = 0; + rsurface.batchskeletaltransform3x4buffer = NULL; + rsurface.batchskeletaltransform3x4offset = 0; + rsurface.batchskeletaltransform3x4size = 0; // we'll only be setting up certain arrays as needed if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t)); @@ -8886,6 +9517,11 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); if (batchneed & BATCHNEED_ARRAY_LIGHTMAP) rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); + if (batchneed & BATCHNEED_ARRAY_SKELETAL) + { + rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4])); + rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4])); + } numvertices = 0; numtriangles = 0; for (i = 0;i < texturenumsurfaces;i++) @@ -8947,6 +9583,22 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const else memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2])); } + if (batchneed & BATCHNEED_ARRAY_SKELETAL) + { + if (rsurface.modelskeletalindex4ub) + { + memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4])); + memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4])); + } + else + { + memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4])); + memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4])); + ub = rsurface.batchskeletalweight4ub + 4*numvertices; + for (j = 0;j < surfacenumvertices;j++) + ub[j*4] = 255; + } + } } RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex); numvertices += surfacenumvertices; @@ -8969,6 +9621,133 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const rsurface.batchnumtriangles = batchnumtriangles; } + // apply skeletal animation that would have been done in the vertex shader + if (rsurface.batchskeletaltransform3x4) + { + const unsigned char *si; + const unsigned char *sw; + const float *t[4]; + const float *b = rsurface.batchskeletaltransform3x4; + float *vp, *vs, *vt, *vn; + float w[4]; + float m[3][4], n[3][4]; + float tp[3], ts[3], tt[3], tn[3]; + r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1; + r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles; + si = rsurface.batchskeletalindex4ub; + sw = rsurface.batchskeletalweight4ub; + vp = rsurface.batchvertex3f; + vs = rsurface.batchsvector3f; + vt = rsurface.batchtvector3f; + vn = rsurface.batchnormal3f; + memset(m[0], 0, sizeof(m)); + memset(n[0], 0, sizeof(n)); + for (i = 0;i < batchnumvertices;i++) + { + t[0] = b + si[0]*12; + if (sw[0] == 255) + { + // common case - only one matrix + m[0][0] = t[0][ 0]; + m[0][1] = t[0][ 1]; + m[0][2] = t[0][ 2]; + m[0][3] = t[0][ 3]; + m[1][0] = t[0][ 4]; + m[1][1] = t[0][ 5]; + m[1][2] = t[0][ 6]; + m[1][3] = t[0][ 7]; + m[2][0] = t[0][ 8]; + m[2][1] = t[0][ 9]; + m[2][2] = t[0][10]; + m[2][3] = t[0][11]; + } + else if (sw[2] + sw[3]) + { + // blend 4 matrices + t[1] = b + si[1]*12; + t[2] = b + si[2]*12; + t[3] = b + si[3]*12; + w[0] = sw[0] * (1.0f / 255.0f); + w[1] = sw[1] * (1.0f / 255.0f); + w[2] = sw[2] * (1.0f / 255.0f); + w[3] = sw[3] * (1.0f / 255.0f); + // blend the matrices + m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3]; + m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3]; + m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3]; + m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3]; + m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3]; + m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3]; + m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3]; + m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3]; + m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3]; + m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3]; + m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3]; + m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3]; + } + else + { + // blend 2 matrices + t[1] = b + si[1]*12; + w[0] = sw[0] * (1.0f / 255.0f); + w[1] = sw[1] * (1.0f / 255.0f); + // blend the matrices + m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1]; + m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1]; + m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1]; + m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1]; + m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1]; + m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1]; + m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1]; + m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1]; + m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1]; + m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1]; + m[2][2] = t[0][10] * w[0] + t[1][10] * w[1]; + m[2][3] = t[0][11] * w[0] + t[1][11] * w[1]; + } + si += 4; + sw += 4; + // modify the vertex + VectorCopy(vp, tp); + vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3]; + vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3]; + vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3]; + vp += 3; + if (vn) + { + // the normal transformation matrix is a set of cross products... + CrossProduct(m[1], m[2], n[0]); + CrossProduct(m[2], m[0], n[1]); + CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m) + VectorCopy(vn, tn); + vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2]; + vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2]; + vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2]; + VectorNormalize(vn); + vn += 3; + if (vs) + { + VectorCopy(vs, ts); + vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2]; + vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2]; + vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2]; + VectorNormalize(vs); + vs += 3; + VectorCopy(vt, tt); + vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2]; + vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2]; + vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2]; + VectorNormalize(vt); + vt += 3; + } + } + } + rsurface.batchskeletaltransform3x4 = NULL; + rsurface.batchskeletalnumtransforms = 0; + } + // q1bsp surfaces rendered in vertex color mode have to have colors // calculated based on lightstyles if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo) @@ -9386,7 +10165,8 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const { // convert the modified arrays to vertex structs // rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t)); -// rsurface.batchvertexmeshbuffer = NULL; +// rsurface.batchvertexmesh_vertexbuffer = NULL; +// rsurface.batchvertexmesh_bufferoffset = 0; if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f); @@ -9410,6 +10190,46 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f) for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f); + if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub) + { + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + { + Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub); + Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub); + } + } + } + + // upload buffer data for the dynamic batch + if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo) + { + if (rsurface.batchvertexmesh) + rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset); + else + { + if (rsurface.batchvertex3f) + rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset); + if (rsurface.batchsvector3f) + rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset); + if (rsurface.batchtvector3f) + rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset); + if (rsurface.batchnormal3f) + rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset); + if (rsurface.batchlightmapcolor4f) + rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset); + if (rsurface.batchtexcoordtexture2f) + rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset); + if (rsurface.batchtexcoordlightmap2f) + rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset); + if (rsurface.batchskeletalindex4ub) + rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset); + if (rsurface.batchskeletalweight4ub) + rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset); + } + if (rsurface.batchelement3s) + rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset); + else if (rsurface.batchelement3i) + rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset); } } @@ -9445,7 +10265,31 @@ void RSurf_DrawBatch(void) } } #endif - 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); + if (rsurface.batchmultidraw) + { + // issue multiple draws rather than copying index data + int numsurfaces = rsurface.batchmultidrawnumsurfaces; + const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist; + int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle; + for (i = 0;i < numsurfaces;) + { + // combine consecutive surfaces as one draw + for (k = i, j = i + 1;j < numsurfaces;k = j, j++) + if (surfacelist[j] != surfacelist[k] + 1) + break; + firstvertex = surfacelist[i]->num_firstvertex; + endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices; + firsttriangle = surfacelist[i]->num_firsttriangle; + endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles; + 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); + i = j; + } + } + else + { + // there is only one consecutive run of index data (may have been combined) + 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); + } } static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface) @@ -9458,14 +10302,14 @@ static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface) r_waterstate_waterplane_t *p; qboolean prepared = false; bestd = 0; - for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) { if(p->camera_entity != rsurface.texture->camera_entity) continue; d = 0; if(!prepared) { - RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface); prepared = true; if(rsurface.batchnumvertices == 0) break; @@ -9512,7 +10356,7 @@ static void RSurf_DrawBatch_GL11_ApplyFog(void) rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); rsurface.passcolor4f_vertexbuffer = 0; rsurface.passcolor4f_bufferoffset = 0; - for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4) + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4) { f = RSurf_FogVertex(v); c2[0] = c[0] * f; @@ -9611,6 +10455,8 @@ static void RSurf_DrawBatch_GL11_Lightmap(float r, float g, float b, float a, qb R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); GL_Color(r, g, b, a); R_Mesh_TexBind(0, rsurface.lightmaptexture); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexMatrix(0, NULL); RSurf_DrawBatch(); } @@ -9791,7 +10637,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_ // transparent sky would be ridiculous if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) return; - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); skyrenderlater = true; RSurf_SetupDepthAndCulling(); GL_DepthMask(true); @@ -9806,21 +10652,18 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_ R_Mesh_ResetTextureState(); if (skyrendermasked) { - R_SetupShader_DepthOrShadow(false); + R_SetupShader_DepthOrShadow(false, false, false); // depth-only (masking) GL_ColorMask(0,0,0,0); // just to make sure that braindead drivers don't draw // anything despite that colormask... GL_BlendFunc(GL_ZERO, GL_ONE); - RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); - if (rsurface.batchvertex3fbuffer) - R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3fbuffer); - else - R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); } else { - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); // fog sky GL_BlendFunc(GL_ONE, GL_ZERO); RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); @@ -9839,7 +10682,7 @@ extern rtexture_t *r_shadow_prepasslightingdiffusetexture; extern rtexture_t *r_shadow_prepasslightingspeculartexture; static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass) { - if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) + if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) return; if (prepass) { @@ -9847,6 +10690,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface GL_DepthMask(true); R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false); RSurf_DrawBatch(); + return; } // bind lightmap texture @@ -9872,7 +10716,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface { // render water or distortion background GL_DepthMask(true); - R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_waterstate.waterplanes + startplaneindex), false); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false); RSurf_DrawBatch(); // blend surface on top GL_DepthMask(false); @@ -9883,7 +10727,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface { // render surface with reflection texture as input GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)); - R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_waterstate.waterplanes + startplaneindex), false); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false); RSurf_DrawBatch(); } } @@ -9989,8 +10833,8 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface R_Mesh_TexBind(1, 0); R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); // generate a color array for the fog pass - R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0); RSurf_DrawBatch_GL11_MakeFogColor(layercolor[0], layercolor[1], layercolor[2], layercolor[3]); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0); RSurf_DrawBatch(); break; default: @@ -10032,7 +10876,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface switch (layer->type) { case TEXTURELAYERTYPE_LITTEXTURE: - if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO) + if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)) { // two-pass lit texture with 2x rgbscale // first the lightmap pass @@ -10065,6 +10909,8 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) RSurf_DrawBatch_GL11_VertexShade(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + else if (FAKELIGHT_ENABLED) + RSurf_DrawBatch_GL11_FakeLight(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); else RSurf_DrawBatch_GL11_VertexColor(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); } @@ -10092,8 +10938,8 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); } // generate a color array for the fog pass - R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0); RSurf_DrawBatch_GL11_MakeFogColor(layer->color[0], layer->color[1], layer->color[2], layer->color[3]); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0); RSurf_DrawBatch(); break; default: @@ -10115,7 +10961,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const float c[4]; // R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); if(rsurface.texture && rsurface.texture->currentskinframe) { @@ -10221,14 +11067,14 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const RSurf_DrawBatch_GL11_ClampColor(); R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.passcolor4f, NULL); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); RSurf_DrawBatch(); } else if (!r_refdef.view.showdebug) { RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices); - for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++) + for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++) { VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1); @@ -10240,7 +11086,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const { RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices); - for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++) + for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++) { unsigned char c = (vi << 3) * (1.0f / 256.0f); VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); @@ -10423,14 +11269,11 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(true); // R_Mesh_ResetTextureState(); - R_SetupShader_DepthOrShadow(false); } RSurf_SetupDepthAndCulling(); - RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist); - if (rsurface.batchvertex3fbuffer) - R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3fbuffer); - else - R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4); + R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); RSurf_DrawBatch(); } if (setup) @@ -10482,7 +11325,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity } -static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, const entity_render_t *queueentity) +static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist) { // transparent surfaces get pushed off into the transparent queue int surfacelistindex; @@ -10491,17 +11334,26 @@ static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++) { surface = texturesurfacelist[surfacelistindex]; - tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; - tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; - tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; + if (r_transparent_sortsurfacesbynearest.integer) + { + tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]); + tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]); + tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]); + } + else + { + tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; + tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; + tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; + } Matrix4x4_Transform(&rsurface.matrix, tempcenter, center); - if (queueentity->transparent_offset) // transparent offset + if (rsurface.entity->transparent_offset) // transparent offset { - center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset; - center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset; - center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset; + center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset; + center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset; + center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset; } - R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight); + 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); } } @@ -10509,20 +11361,17 @@ static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msu { if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) return; - if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) + if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) return; RSurf_SetupDepthAndCulling(); - RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist); - if (rsurface.batchvertex3fbuffer) - R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3fbuffer); - else - R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4); RSurf_DrawBatch(); } static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass) { - const entity_render_t *queueentity = r_refdef.scene.worldentity; CHECKGLERROR if (depthonly) R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist); @@ -10531,7 +11380,7 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf if (!rsurface.texture->currentnumlayers) return; if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) - R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity); + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); else R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass); } @@ -10539,11 +11388,11 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); else if (!rsurface.texture->currentnumlayers) return; - else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity) + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)))) { // in the deferred case, transparent surfaces were queued during prepass if (!r_shadow_usingdeferredprepass) - R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity); + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); } else { @@ -10553,7 +11402,7 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf CHECKGLERROR } -void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass) +static void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass) { int i, j; texture_t *texture; @@ -10599,7 +11448,7 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in R_FrameData_ReturnToMark(); } -static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity, qboolean prepass) +static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass) { CHECKGLERROR if (depthonly) @@ -10609,7 +11458,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf if (!rsurface.texture->currentnumlayers) return; if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) - R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity); + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); else R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass); } @@ -10617,11 +11466,11 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); else if (!rsurface.texture->currentnumlayers) return; - else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity) + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)))) { // in the deferred case, transparent surfaces were queued during prepass if (!r_shadow_usingdeferredprepass) - R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity); + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); } else { @@ -10631,7 +11480,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf CHECKGLERROR } -void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass) +static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass) { int i, j; texture_t *texture; @@ -10672,7 +11521,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa ; } // render the range of surfaces - R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass); + R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass); } R_FrameData_ReturnToMark(); } @@ -10697,7 +11546,7 @@ unsigned short locboxelements[6*2*3] = 20,21,22, 20,22,23 }; -void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { int i, j; cl_locnode_t *loc = (cl_locnode_t *)ent; @@ -10736,7 +11585,7 @@ void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, in vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i]; R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0); } @@ -10749,7 +11598,7 @@ void R_DrawLocs(void) for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++) { VectorLerp(loc->mins, 0.5f, loc->maxs, center); - R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL); } } @@ -11194,7 +12043,6 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent) else frametime = 0; decalsystem->lastupdatetime = r_refdef.scene.time; - decal = decalsystem->decals; numdecals = decalsystem->numdecals; for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++) @@ -11271,7 +12119,6 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent) RSurf_ActiveModelEntity(ent, false, false, false); decalsystem->lastupdatetime = r_refdef.scene.time; - decal = decalsystem->decals; faderate = 1.0f / max(0.001f, cl_decals_fadetime.value); @@ -11350,7 +12197,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent) if (numtris > 0) { - r_refdef.stats.drawndecals += numtris; + r_refdef.stats[r_stat_drawndecals] += numtris; // now render the decals all at once // (this assumes they all use one particle font texture!) @@ -11363,7 +12210,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent) GL_DepthTest(true); GL_CullFace(GL_NONE); GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false); R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0); } } @@ -11388,7 +12235,7 @@ static void R_DrawModelDecals(void) for (i = 0;i < r_refdef.scene.numentities;i++) numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals; - r_refdef.stats.totaldecals += numdecals; + r_refdef.stats[r_stat_totaldecals] += numdecals; if (r_showsurfaces.integer) return; @@ -11405,13 +12252,12 @@ static void R_DrawModelDecals(void) } extern cvar_t mod_collision_bih; -void R_DrawDebugModel(void) +static void R_DrawDebugModel(void) { entity_render_t *ent = rsurface.entity; - int i, j, k, l, flagsmask; + int i, j, flagsmask; const msurface_t *surface; dp_model_t *model = ent->model; - vec3_t v; if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity) return; @@ -11420,7 +12266,7 @@ void R_DrawDebugModel(void) { float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f; flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL; - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); GL_DepthTest(false); GL_DepthMask(false); GL_DepthRange(0, 1); @@ -11450,7 +12296,7 @@ void R_DrawDebugModel(void) flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL; // R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false); + R_SetupShader_Generic_NoTexture(false, false); GL_DepthRange(0, 1); GL_DepthTest(!r_showdisabledepthtest.integer); GL_DepthMask(false); @@ -11460,13 +12306,12 @@ void R_DrawDebugModel(void) { int triangleindex; int bihleafindex; - qboolean cullbox = ent == r_refdef.scene.worldentity; + qboolean cullbox = false; const q3mbrush_t *brush; const bih_t *bih = &model->collision_bih; const bih_leaf_t *bihleaf; float vertex3f[3][3]; GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value); - cullbox = false; for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++) { if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs)) @@ -11544,6 +12389,8 @@ void R_DrawDebugModel(void) if (r_shownormals.value != 0 && qglBegin) { + int l, k; + vec3_t v; if (r_showdisabledepthtest.integer) { GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -11620,7 +12467,6 @@ void R_DrawDebugModel(void) #endif } -extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); int r_maxsurfacelist = 0; const msurface_t **r_surfacelist = NULL; void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass) @@ -11710,9 +12556,9 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep // add to stats if desired if (r_speeds.integer && !skysurfaces && !depthonly) { - r_refdef.stats.world_surfaces += numsurfacelist; + r_refdef.stats[r_stat_world_surfaces] += numsurfacelist; for (j = 0;j < numsurfacelist;j++) - r_refdef.stats.world_triangles += r_surfacelist[j]->num_triangles; + r_refdef.stats[r_stat_world_triangles] += r_surfacelist[j]->num_triangles; } rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity @@ -11840,18 +12686,15 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr } } } - if (update) - for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) - if (update[j]) - R_BuildLightMap(ent, surfaces + j); + R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass); // add to stats if desired if (r_speeds.integer && !skysurfaces && !depthonly) { - r_refdef.stats.entities_surfaces += numsurfacelist; + r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist; for (j = 0;j < numsurfacelist;j++) - r_refdef.stats.entities_triangles += r_surfacelist[j]->num_triangles; + r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles; } rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity @@ -11873,6 +12716,9 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i texture.offsetscale = 1; texture.specularscalemod = 1; texture.specularpowermod = 1; + texture.transparentsort = TRANSPARENTSORT_DISTANCE; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". surface.texture = &texture; surface.num_triangles = numtriangles;