Fixed a bug with spec maps.

This commit is contained in:
Justin Marshall
2026-05-07 12:26:46 -07:00
parent 1a6bc0c447
commit 469be38dbe
6 changed files with 434 additions and 54 deletions
+80 -26
View File
@@ -2315,6 +2315,8 @@ struct glRaytracingLightingState_t
bool externalDenoiser;
ID3D12Resource* emissiveTexture;
DXGI_FORMAT emissiveFormat;
ID3D12Resource* specularTexture;
DXGI_FORMAT specularFormat;
bool uploadToCurrentFrameResource;
bool initialized;
@@ -2341,6 +2343,8 @@ struct glRaytracingLightingState_t
externalDenoiser = false;
emissiveTexture = nullptr;
emissiveFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
specularTexture = nullptr;
specularFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
uploadToCurrentFrameResource = false;
initialized = false;
}
@@ -2364,14 +2368,15 @@ enum glRaytracingLightingDescriptorIndex_t
GLR_DESC_HISTORY_SRV = 9,
GLR_DESC_TEMPORAL_SRV = 10,
GLR_DESC_EMISSIVE_SRV = 11,
GLR_DESC_PATHTRACE_UAV = 12,
GLR_DESC_DENOISE_A_UAV = 13,
GLR_DESC_DENOISE_B_UAV = 14,
GLR_DESC_OUTPUT_UAV = 15,
GLR_DESC_TEMPORAL_UAV = 16,
GLR_DESC_HISTORY_UAV = 17,
GLR_DESC_COUNT = 18,
GLR_DESC_SRV_COUNT = 12,
GLR_DESC_SPECULAR_SRV = 12,
GLR_DESC_PATHTRACE_UAV = 13,
GLR_DESC_DENOISE_A_UAV = 14,
GLR_DESC_DENOISE_B_UAV = 15,
GLR_DESC_OUTPUT_UAV = 16,
GLR_DESC_TEMPORAL_UAV = 17,
GLR_DESC_HISTORY_UAV = 18,
GLR_DESC_COUNT = 19,
GLR_DESC_SRV_COUNT = 13,
GLR_DESC_UAV_COUNT = 6
};
@@ -2466,6 +2471,7 @@ Texture2D<float4> gNormalTex : register(t3);
Texture2D<float4> gPositionTex : register(t4);
RaytracingAccelerationStructure gSceneBVH : register(t5);
Texture2D<float4> gEmissiveTex : register(t11);
Texture2D<float4> gSpecularTex : register(t12);
RWTexture2D<float4> gOutputTex : register(u0);
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0;
@@ -3252,10 +3258,8 @@ float Doom3SpecularLookup(float x)
float3 Doom3PseudoSpecularMask(float3 baseAlbedo)
{
// Doom 3 normally uses a dedicated specular map.
// This pass does not have one bound, so DO NOT square diffuse albedo.
// Squaring albedo makes dark Doom 3 textures lose all specular response.
//
// Use luminance only as a weak hint, with a neutral floor.
// This fallback is only used for pixels whose specular G-buffer says no
// specular map was written by the raster pass.
float lum = dot(saturate(baseAlbedo), float3(0.299, 0.587, 0.114));
float specStrength = lerp(0.22, 0.72, saturate(lum * 1.35));
@@ -3268,6 +3272,18 @@ float3 Doom3PseudoSpecularMask(float3 baseAlbedo)
return max(tintedSpec, float3(0.18, 0.18, 0.18));
}
float3 LoadSceneSpecularAlbedo(uint2 pixel, float3 baseAlbedo)
{
float4 specSample = gSpecularTex.Load(int3(pixel, 0));
// The raster G-buffer writer stores alpha as a validity bit. This matters
// for black specular maps: black should mean zero specular, not "missing map".
if (specSample.a > 0.5)
return saturate(specSample.rgb);
return Doom3PseudoSpecularMask(baseAlbedo);
}
float3 ComputeSpecular(
float3 N,
float3 V,
@@ -3276,7 +3292,7 @@ float3 ComputeSpecular(
float lightIntensity,
float atten,
float shadow,
float3 baseAlbedo)
float3 specularAlbedo)
{
if (gEnableSpecular == 0)
return 0.0;
@@ -3301,7 +3317,7 @@ float3 ComputeSpecular(
float specTerm = Doom3SpecularLookup(NdotH);
float3 specMask = Doom3PseudoSpecularMask(baseAlbedo);
float3 specMask = saturate(specularAlbedo);
// Doom 3's interaction pass is strongly additive. Keep it punchy,
// but clamp enough to avoid fireflies with stochastic light sampling.
@@ -3611,7 +3627,7 @@ float3 EstimatePathTracedSky(float3 worldPos, float3 N, inout uint rng)
return accum * 0.55;
}
float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
{
specularOut = 0.0;
@@ -3663,7 +3679,7 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
if (Lgt.pointRadiusPad <= 0.5)
specAccum += ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, baseAlbedo);
specAccum += ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
diffuseAccum += Lgt.color * (Lgt.intensity * atten * NdotLWrap * shadow);
}
@@ -3673,7 +3689,7 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
return diffuseAccum * invSamples;
}
float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 baseAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
{
specularOut = 0.0;
@@ -3693,12 +3709,12 @@ float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 base
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
if (Lgt.pointRadiusPad <= 0.5)
specularOut = ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, baseAlbedo);
specularOut = ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
return Lgt.color * (Lgt.intensity * atten * NdotLWrap * shadow);
}
float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
{
specularOut = 0.0;
@@ -3764,7 +3780,7 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
Lgt.intensity * faceTerm,
1.0,
shadow,
baseAlbedo) * atten;
specularAlbedo) * atten;
}
diffuseAccum += clamp(Lgt.color * (Lgt.intensity * NdotL * faceTerm * atten * shadow), 0.0, 4.0);
@@ -3961,21 +3977,22 @@ float3 EstimateShadowedBounceLight(uint2 hitPixel, float3 hitPos, float3 hitN, f
{
float3 spec = 0.0;
float3 diffuse = 0.0;
float3 hitSpecularAlbedo = LoadSceneSpecularAlbedo(hitPixel, hitAlbedo);
// Use the same visibility-capable direct-light samplers as the primary hit.
// This supplies proper next-event estimation at secondary hits instead of the
// old unoccluded light-list approximation.
if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
{
diffuse = PathTraceDirectPointLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, Lgt, rng, spec);
diffuse = PathTraceDirectPointLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, Lgt, rng, spec);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
{
diffuse = PathTraceDirectSpotLight(hitPos, hitN, hitV, hitAlbedo, Lgt, rng, spec);
diffuse = PathTraceDirectSpotLight(hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, Lgt, rng, spec);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
{
diffuse = PathTraceDirectRectLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, Lgt, rng, spec);
diffuse = PathTraceDirectRectLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, Lgt, rng, spec);
}
return clamp(diffuse, 0.0, 12.0);
@@ -4369,6 +4386,7 @@ float3 PathTraceDeterministicLighting(
float3 N,
float3 V,
float3 baseAlbedo,
float3 specularAlbedo,
bool isSkeletal,
float cavity,
float ao,
@@ -4411,15 +4429,15 @@ float3 PathTraceDeterministicLighting(
if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
{
diffuse = PathTraceDirectPointLight(pixel, worldPos, N, V, baseAlbedo, Lgt, directRng, spec);
diffuse = PathTraceDirectPointLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, Lgt, directRng, spec);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
{
diffuse = PathTraceDirectSpotLight(worldPos, N, V, baseAlbedo, Lgt, directRng, spec);
diffuse = PathTraceDirectSpotLight(worldPos, N, V, baseAlbedo, specularAlbedo, Lgt, directRng, spec);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
{
diffuse = PathTraceDirectRectLight(pixel, worldPos, N, V, baseAlbedo, Lgt, directRng, spec);
diffuse = PathTraceDirectRectLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, Lgt, directRng, spec);
}
lightingAccum += diffuse;
@@ -4452,6 +4470,7 @@ void RayGen()
}
float3 baseAlbedo = albedoSample.rgb;
float3 specularAlbedo = LoadSceneSpecularAlbedo(pixel, baseAlbedo);
float4 positionSample = gPositionTex.Load(int3(pixel, 0));
float3 worldPos = positionSample.xyz;
float4 normalSample = LoadSceneNormal(pixel);
@@ -4502,6 +4521,7 @@ void RayGen()
N,
V,
baseAlbedo,
specularAlbedo,
isSkeletal,
cavity,
ao,
@@ -5780,6 +5800,30 @@ static void glRaytracingLightingCreatePerPassDescriptors(
g_glRaytracingCmd.device->CreateShaderResourceView(g_glRaytracingLighting.emissiveTexture, &emissiveSrv,
glRaytracingOffsetCpu(base, g_glRaytracingLighting.descriptorStride, GLR_DESC_EMISSIVE_SRV));
D3D12_SHADER_RESOURCE_VIEW_DESC specularSrv = {};
specularSrv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
specularSrv.Texture2D.MipLevels = 1;
ID3D12Resource* specularResource = g_glRaytracingLighting.specularTexture;
if (specularResource)
{
specularSrv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
specularSrv.Format = g_glRaytracingLighting.specularFormat;
}
else
{
// Bind a harmless fallback descriptor when the shim has not provided a
// specular G-buffer. The shader sees alpha zero and uses the legacy fallback.
specularResource = pass->albedoTexture;
specularSrv.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2,
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0);
specularSrv.Format = pass->albedoFormat;
}
g_glRaytracingCmd.device->CreateShaderResourceView(specularResource, &specularSrv,
glRaytracingOffsetCpu(base, g_glRaytracingLighting.descriptorStride, GLR_DESC_SPECULAR_SRV));
D3D12_UNORDERED_ACCESS_VIEW_DESC rayOutputUav = {};
rayOutputUav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
rayOutputUav.Format = GL_RAYTRACING_DENOISE_FORMAT;
@@ -6428,6 +6472,16 @@ void glRaytracingLightingSetEmissiveInput(ID3D12Resource* texture, DXGI_FORMAT f
: format;
}
void glRaytracingLightingSetSpecularInput(ID3D12Resource* texture, DXGI_FORMAT format)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
g_glRaytracingLighting.specularTexture = texture;
g_glRaytracingLighting.specularFormat = (format == DXGI_FORMAT_UNKNOWN)
? DXGI_FORMAT_R8G8B8A8_UNORM
: format;
}
bool glRaytracingLightingExecuteForScene(const glRaytracingLightingPassDesc_t* pass, glRaytracingSceneHandle_t worldHandle)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
+313 -22
View File
@@ -158,6 +158,9 @@ using Microsoft::WRL::ComPtr;
#ifndef GL_GLOW_MAP_BINDING_QD3D12
#define GL_GLOW_MAP_BINDING_QD3D12 0x6005
#endif
#ifndef GL_SPECULAR_MAP_BINDING_QD3D12
#define GL_SPECULAR_MAP_BINDING_QD3D12 0x6006
#endif
// Optional material/ray-visibility tags for the DXR path. These are private
// shim enums; they deliberately live next to the normal-map compatibility enums.
@@ -220,6 +223,11 @@ void APIENTRY glTextureGlowMap(GLuint texture, GLboolean isGlowMap);
void APIENTRY glBindGlowMapTexture(GLuint texture);
void APIENTRY glGlowMapTexture(GLuint texture);
void APIENTRY glGlowMapStrengthf(GLfloat strength);
void APIENTRY glTagTextureSpecularMap(GLuint texture, GLboolean isSpecularMap);
void APIENTRY glTextureSpecularMap(GLuint texture, GLboolean isSpecularMap);
void APIENTRY glBindSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapStrengthf(GLfloat strength);
void APIENTRY glRaytracingMaterialFlagsQD3D12(GLuint flags);
void APIENTRY glRaytracingMaterialFlagQD3D12(GLuint flag, GLboolean enable);
@@ -230,6 +238,7 @@ void glRaytracingLightingSetExternalDenoiser(int enable);
void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_t maxBounces, int enableDenoiser, float denoiseStrength);
void glRaytracingLightingSetVolumetricScattering(glRaytracingLight_t* light, float strength);
void glRaytracingLightingSetEmissiveInput(ID3D12Resource* texture, DXGI_FORMAT format);
void glRaytracingLightingSetSpecularInput(ID3D12Resource* texture, DXGI_FORMAT format);
void glRaytracingSetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle, uint32_t materialFlags);
void glRaytracingSetMeshGlass(glRaytracingMeshHandle_t meshHandle, int isGlass);
uint32_t glRaytracingGetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle);
@@ -354,11 +363,14 @@ enum QD3D12RTVSlotGroup
QD3D12_RTV_VELOCITY_RESOLVED = 8,
QD3D12_RTV_EMISSIVE_RESOLVED = 9,
QD3D12_RTV_BACKBUFFER = 10,
QD3D12_RTV_GROUP_COUNT = 11
QD3D12_RTV_SPECULAR_RENDER = 11,
QD3D12_RTV_SPECULAR_RESOLVED = 12,
QD3D12_RTV_GROUP_COUNT = 13
};
static const DXGI_FORMAT QD3D12_SceneColorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
static const DXGI_FORMAT QD3D12_EmissiveFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
static const DXGI_FORMAT QD3D12_SpecularAlbedoFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
static const DXGI_FORMAT QD3D12_StreamlineOutputFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
static const DXGI_FORMAT QD3D12_VelocityFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
static const DXGI_FORMAT QD3D12_DepthFormat = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
@@ -488,6 +500,7 @@ struct TextureResource
// from any active texture unit.
bool isNormalMap = false;
bool isGlowMap = false;
bool isSpecularMap = false;
};
static void QD3D12_ShutdownMipWorkers();
@@ -529,6 +542,7 @@ struct DrawConstants
float jitterPixels[2];
float prevJitterPixels[2];
float _motionPad[4];
float materialMapPad[4];
float texComb0RGB[4];
float texComb0Alpha[4];
@@ -562,7 +576,7 @@ struct GLBufferObject
const char* vendor = "Justin Marshall";
const char* renderer = "Quake D3D12 Wrapper";
const char* version = "1.1-quake-d3d12";
const char* extensions = "GL_SGIS_multitexture GL_ARB_multitexture GL_EXT_texture_env_add GL_ARB_texture_env_combine GL_ARB_texture_compression GL_EXT_texture_compression_s3tc GL_ARB_vertex_program GL_ARB_fragment_program GL_EXT_texture_cube_map GL_EXT_depth_bounds_test GL_EXT_stencil_two_side GL_ATI_separate_stencil GL_QD3D12_normal_map GL_QD3D12_glow_map GL_QD3D12_glass_material GL_QD3D12_volumetric_light";
const char* extensions = "GL_SGIS_multitexture GL_ARB_multitexture GL_EXT_texture_env_add GL_ARB_texture_env_combine GL_ARB_texture_compression GL_EXT_texture_compression_s3tc GL_ARB_vertex_program GL_ARB_fragment_program GL_EXT_texture_cube_map GL_EXT_depth_bounds_test GL_EXT_stencil_two_side GL_ATI_separate_stencil GL_QD3D12_normal_map GL_QD3D12_glow_map GL_QD3D12_specular_map GL_QD3D12_glass_material GL_QD3D12_volumetric_light";
enum TexEnvModeShader
{
@@ -610,6 +624,9 @@ struct BatchKey
UINT glowMapSrvIndex = 0;
float useGlowMap = 0.0f;
float glowMapStrength = 1.0f;
UINT specularMapSrvIndex = 0;
float useSpecularMap = 0.0f;
float specularMapStrength = 1.0f;
bool useARBPrograms = false;
GLuint arbVertexProgram = 0;
@@ -721,6 +738,9 @@ static bool BatchKeyEquals(const BatchKey& a, const BatchKey& b)
a.glowMapSrvIndex == b.glowMapSrvIndex &&
a.useGlowMap == b.useGlowMap &&
a.glowMapStrength == b.glowMapStrength &&
a.specularMapSrvIndex == b.specularMapSrvIndex &&
a.useSpecularMap == b.useSpecularMap &&
a.specularMapStrength == b.specularMapStrength &&
a.alphaRef == b.alphaRef &&
a.alphaFunc == b.alphaFunc &&
a.useTex0 == b.useTex0 &&
@@ -827,6 +847,9 @@ struct QD3D12Window
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> emissiveBuffers;
D3D12_RESOURCE_STATES emissiveBufferState[QD3D12_FrameCount] = {};
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> specularBuffers;
D3D12_RESOURCE_STATES specularBufferState[QD3D12_FrameCount] = {};
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> sceneColorMsaaBuffers;
D3D12_RESOURCE_STATES sceneColorMsaaState[QD3D12_FrameCount] = {};
@@ -842,6 +865,9 @@ struct QD3D12Window
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> emissiveMsaaBuffers;
D3D12_RESOURCE_STATES emissiveMsaaState[QD3D12_FrameCount] = {};
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> specularMsaaBuffers;
D3D12_RESOURCE_STATES specularMsaaState[QD3D12_FrameCount] = {};
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> backBuffers;
D3D12_RESOURCE_STATES backBufferState[QD3D12_FrameCount] = {};
@@ -879,6 +905,10 @@ struct QD3D12Window
D3D12_CPU_DESCRIPTOR_HANDLE emissiveSrvCpu[QD3D12_FrameCount]{};
D3D12_GPU_DESCRIPTOR_HANDLE emissiveSrvGpu[QD3D12_FrameCount]{};
UINT specularSrvIndex[QD3D12_FrameCount] = { UINT_MAX, UINT_MAX };
D3D12_CPU_DESCRIPTOR_HANDLE specularSrvCpu[QD3D12_FrameCount]{};
D3D12_GPU_DESCRIPTOR_HANDLE specularSrvGpu[QD3D12_FrameCount]{};
UINT slOutputSrvIndex[QD3D12_FrameCount] = { UINT_MAX, UINT_MAX };
D3D12_CPU_DESCRIPTOR_HANDLE slOutputSrvCpu[QD3D12_FrameCount]{};
D3D12_GPU_DESCRIPTOR_HANDLE slOutputSrvGpu[QD3D12_FrameCount]{};
@@ -907,6 +937,10 @@ struct QD3D12Window
D3D12_CPU_DESCRIPTOR_HANDLE emissiveMsaaSrvCpu[QD3D12_FrameCount]{};
D3D12_GPU_DESCRIPTOR_HANDLE emissiveMsaaSrvGpu[QD3D12_FrameCount]{};
UINT specularMsaaSrvIndex[QD3D12_FrameCount] = { UINT_MAX, UINT_MAX };
D3D12_CPU_DESCRIPTOR_HANDLE specularMsaaSrvCpu[QD3D12_FrameCount]{};
D3D12_GPU_DESCRIPTOR_HANDLE specularMsaaSrvGpu[QD3D12_FrameCount]{};
D3D12_VIEWPORT viewport{};
D3D12_RECT scissor{};
@@ -1180,6 +1214,8 @@ struct GLState
float currentNormalMapYSign = 1.0f;
GLuint currentGlowMapTexture = 0;
float currentGlowMapStrength = 1.0f;
GLuint currentSpecularMapTexture = 0;
float currentSpecularMapStrength = 1.0f;
ImmediateVertexBuffer immediateVerts;
GLenum matrixMode = GL_MODELVIEW;
@@ -1770,6 +1806,12 @@ static D3D12_CPU_DESCRIPTOR_HANDLE CurrentEmissiveRTV()
return QD3D12_RtvAt(w, QD3D12_RTV_EMISSIVE_RENDER, w.frameIndex);
}
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentSpecularRTV()
{
QD3D12Window& w = *g_currentWindow;
return QD3D12_RtvAt(w, QD3D12_RTV_SPECULAR_RENDER, w.frameIndex);
}
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentResolvedSceneColorRTV()
{
QD3D12Window& w = *g_currentWindow;
@@ -1800,6 +1842,12 @@ static D3D12_CPU_DESCRIPTOR_HANDLE CurrentResolvedEmissiveRTV()
return QD3D12_RtvAt(w, QD3D12_RTV_EMISSIVE_RESOLVED, w.frameIndex);
}
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentResolvedSpecularRTV()
{
QD3D12Window& w = *g_currentWindow;
return QD3D12_RtvAt(w, QD3D12_RTV_SPECULAR_RESOLVED, w.frameIndex);
}
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentBackBufferRTV()
{
QD3D12Window& w = *g_currentWindow;
@@ -1894,6 +1942,12 @@ static bool QD3D12_IsTextureTaggedGlowMap(GLuint id)
return tex && tex->isGlowMap;
}
static bool QD3D12_IsTextureTaggedSpecularMap(GLuint id)
{
TextureResource* tex = QD3D12_FindTextureResource(id);
return tex && tex->isSpecularMap;
}
static TextureResource* QD3D12_SelectNormalMapTexture(TextureResource* const* allTextures)
{
// Explicit material binding wins. This lets callers bind a normal map even
@@ -1965,6 +2019,45 @@ static TextureResource* QD3D12_SelectGlowMapTexture(TextureResource* const* allT
return nullptr;
}
static TextureResource* QD3D12_SelectSpecularMapTexture(TextureResource* const* allTextures)
{
// Explicit material binding wins. Tagged specular maps can also be discovered
// from any fixed-function texture unit without consuming the diffuse/lightmap slots.
if (g_gl.currentSpecularMapTexture != 0)
{
TextureResource* explicitSpecular = QD3D12_FindTextureResource(g_gl.currentSpecularMapTexture);
if (explicitSpecular)
{
// Avoid common cross-role binding mistakes. A texture tagged only as a
// normal or glow map should not silently become specular albedo.
if ((explicitSpecular->isNormalMap && !explicitSpecular->isSpecularMap) ||
(explicitSpecular->isGlowMap && !explicitSpecular->isSpecularMap))
return nullptr;
return explicitSpecular;
}
}
if (allTextures)
{
for (UINT i = 0; i < QD3D12_MaxTextureUnits; ++i)
{
TextureResource* tex = allTextures[i];
if (tex && tex != &g_gl.whiteTexture && tex->isSpecularMap)
return tex;
}
}
for (UINT i = 0; i < QD3D12_MaxTextureUnits; ++i)
{
TextureResource* tex = QD3D12_FindTextureResource(g_gl.boundTexture[i]);
if (tex && tex->isSpecularMap)
return tex;
}
return nullptr;
}
static const uint8_t* QD3D12_ResolveArrayPointer(const void* ptr)
{
if (g_gl.boundArrayBuffer != 0)
@@ -2109,6 +2202,7 @@ cbuffer DrawCB : register(b0)
float2 gJitterPixels;
float2 gPrevJitterPixels;
float4 gMotionPad;
float4 gMaterialMapPad;
float4 gTexComb0RGB;
float4 gTexComb0Alpha;
@@ -2126,15 +2220,19 @@ cbuffer DrawCB : register(b0)
#define gParallaxScale 0.0
#define gUseGlowMap gMotionPad.w
#define gGlowMapStrength gMotionPad.w
#define gUseSpecularMap gMaterialMapPad.x
#define gSpecularMapStrength gMaterialMapPad.y
Texture2D gTex0 : register(t0);
Texture2D gTex1 : register(t1);
Texture2D gNormalMap : register(t2);
Texture2D gGlowMap : register(t3);
Texture2D gSpecularMap : register(t4);
SamplerState gSamp0 : register(s0);
SamplerState gSamp1 : register(s1);
SamplerState gSamp2 : register(s2);
SamplerState gSamp3 : register(s3);
SamplerState gSamp4 : register(s4);
struct VSIn
{
@@ -2171,6 +2269,7 @@ struct PSOut
float4 position : SV_Target2;
float4 velocity : SV_Target3;
float4 emissive : SV_Target4;
float4 specular : SV_Target5;
};
float4 QD3D12_GetTexEnvSource(float source, float4 texel, float4 primary, float4 previous, float4 constantColor)
@@ -2515,6 +2614,26 @@ float4 BuildGlowEmission(VSOut i)
return QD3D12_SampleGlow(i);
}
float4 BuildSpecularAlbedo(VSOut i)
{
if (gUseSpecularMap <= 0.0)
return float4(0.0, 0.0, 0.0, 0.0);
float4 spec = gSpecularMap.Sample(gSamp4, QD3D12_BuildMaterialUV0(i));
float strength = max(gSpecularMapStrength, 0.0);
// RGB-only legacy spec maps are uploaded with forced opaque alpha. For real
// RGBA spec maps, alpha is treated as an artist mask over RGB. The alpha we
// write to the G-buffer is not the brightness mask; it is a presence bit so
// the DXR pass can distinguish "no spec map bound" from an intentional
// black spec-map texel.
bool alphaLooksForcedOpaque = (spec.a >= 0.999);
float alphaMask = alphaLooksForcedOpaque ? 1.0 : saturate(spec.a);
float3 specRgb = saturate(spec.rgb) * alphaMask * strength;
return float4(specRgb, 1.0);
}
float2 ClipToUv(float4 clipPos)
{
float2 ndc = clipPos.xy / max(abs(clipPos.w), 1e-6);
@@ -2572,6 +2691,7 @@ PSOut PSMain(VSOut i)
o.position = float4(i.worldPos, i.attr.x);
o.velocity = BuildVelocity(i);
o.emissive = BuildGlowEmission(i);
o.specular = BuildSpecularAlbedo(i);
return o;
}
@@ -2584,6 +2704,7 @@ PSOut PSMainAlphaTest(VSOut i)
o.position = float4(i.worldPos, i.attr.x);
o.velocity = BuildVelocity(i);
o.emissive = BuildGlowEmission(i);
o.specular = BuildSpecularAlbedo(i);
return o;
}
@@ -2595,6 +2716,7 @@ PSOut PSMainUntextured(VSOut i)
o.position = float4(i.worldPos, i.attr.x);
o.velocity = BuildVelocity(i);
o.emissive = float4(0.0, 0.0, 0.0, 0.0);
o.specular = BuildSpecularAlbedo(i);
return o;
}
@@ -2626,6 +2748,7 @@ Texture2DMS<float4> gNormalMS : register(t2);
Texture2DMS<float4> gPositionMS : register(t3);
Texture2DMS<float4> gVelocityMS : register(t4);
Texture2DMS<float4> gEmissiveMS : register(t5);
Texture2DMS<float4> gSpecularMS : register(t6);
SamplerState gSamp0 : register(s0);
struct VSOut
@@ -2765,6 +2888,7 @@ struct PSGBufferPointResolveOut
float4 position : SV_Target1;
float4 velocity : SV_Target2;
float4 emissive : SV_Target3;
float4 specular : SV_Target4;
};
PSGBufferPointResolveOut PSGBufferPointResolveMS(VSOut i)
@@ -2788,6 +2912,7 @@ PSGBufferPointResolveOut PSGBufferPointResolveMS(VSOut i)
o.position = gPositionMS.Load(int2(srcPixel), sampleIndex);
o.velocity = gVelocityMS.Load(int2(srcPixel), sampleIndex);
o.emissive = gEmissiveMS.Load(int2(srcPixel), sampleIndex);
o.specular = gSpecularMS.Load(int2(srcPixel), sampleIndex);
return o;
}
@@ -3219,6 +3344,19 @@ static BatchKey BuildCurrentBatchKey(GLenum originalMode, const TextureResource*
}
key.glowMapStrength = g_gl.currentGlowMapStrength;
TextureResource* specularMap = QD3D12_SelectSpecularMapTexture(allTextures);
if (specularMap && specularMap->texture && specularMap->srvIndex != UINT_MAX)
{
key.specularMapSrvIndex = specularMap->srvIndex;
key.useSpecularMap = 1.0f;
}
else
{
key.specularMapSrvIndex = g_gl.whiteTexture.srvIndex;
key.useSpecularMap = 0.0f;
}
key.specularMapStrength = g_gl.currentSpecularMapStrength;
key.useARBPrograms = QD3D12ARB_IsActive();
if (key.useARBPrograms)
{
@@ -4546,7 +4684,7 @@ static void QD3D12_RunUpscalerOrBlit(QD3D12Window& w)
sl::Resource mvec = { sl::ResourceType::eTex2d, w.velocityBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) };
sl::Resource specularMvec = { sl::ResourceType::eTex2d, w.velocityBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) };
sl::Resource diffuseAlbedo = { sl::ResourceType::eTex2d, w.sceneColorBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) };
sl::Resource specularAlbedo = { sl::ResourceType::eTex2d, w.sceneColorBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) };
sl::Resource specularAlbedo = { sl::ResourceType::eTex2d, w.specularBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) };
sl::Resource normalRoughness = { sl::ResourceType::eTex2d, w.normalBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) };
sl::ResourceTag tags[] =
@@ -4795,6 +4933,7 @@ static bool QD3D12_CanUseGBufferSampleCount(UINT sampleCount)
// QD3D12_PointResolveMsaaGBufferToSingleSample() point-loads one sample.
QD3D12_FormatSupportsSampleCount(DXGI_FORMAT_R16G16B16A16_FLOAT, sampleCount) &&
QD3D12_FormatSupportsSampleCount(QD3D12_VelocityFormat, sampleCount) &&
QD3D12_FormatSupportsSampleCount(QD3D12_SpecularAlbedoFormat, sampleCount) &&
QD3D12_FormatSupportsSampleCount(QD3D12_DepthDsvFormat, sampleCount);
}
@@ -4938,6 +5077,7 @@ static void QD3D12_CreateRTVsForWindow(QD3D12Window& w)
const float normalClear[4] = { 0.0f, 0.0f, 1.0f, 0.5f };
const float positionClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float velocityClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float specularClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const bool useMsaa = QD3D12_GBufferMsaaEnabled();
const UINT msaaSamples = QD3D12_GBufferSampleCount();
@@ -5073,6 +5213,25 @@ static void QD3D12_CreateRTVsForWindow(QD3D12Window& w)
}
}
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
{
if (useMsaa)
{
CreateTexture2D(w.specularMsaaBuffers[i], w.specularMsaaState[i], QD3D12_SpecularAlbedoFormat, specularClear, true,
w.renderWidth, w.renderHeight, msaaSamples, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
QD3D12_RtvAt(w, QD3D12_RTV_SPECULAR_RENDER, i), true);
CreateTexture2D(w.specularBuffers[i], w.specularBufferState[i], QD3D12_SpecularAlbedoFormat, specularClear, false,
w.renderWidth, w.renderHeight, 1, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
QD3D12_RtvAt(w, QD3D12_RTV_SPECULAR_RESOLVED, i), true);
}
else
{
CreateTexture2D(w.specularBuffers[i], w.specularBufferState[i], QD3D12_SpecularAlbedoFormat, specularClear, true,
w.renderWidth, w.renderHeight, 1, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
QD3D12_RtvAt(w, QD3D12_RTV_SPECULAR_RENDER, i), true);
}
}
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
{
D3D12_CPU_DESCRIPTOR_HANDLE backBufferRtv = QD3D12_RtvAt(w, QD3D12_RTV_BACKBUFFER, i);
@@ -5165,6 +5324,9 @@ static void QD3D12_CreateRTVsForWindow(QD3D12Window& w)
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
CreateTextureSrv(w.emissiveBuffers[i].Get(), QD3D12_EmissiveFormat, w.emissiveSrvIndex[i], w.emissiveSrvCpu[i], w.emissiveSrvGpu[i]);
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
CreateTextureSrv(w.specularBuffers[i].Get(), QD3D12_SpecularAlbedoFormat, w.specularSrvIndex[i], w.specularSrvCpu[i], w.specularSrvGpu[i]);
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
CreateTextureSrv(w.slOutputBuffers[i].Get(), QD3D12_StreamlineOutputFormat, w.slOutputSrvIndex[i], w.slOutputSrvCpu[i], w.slOutputSrvGpu[i]);
@@ -5181,6 +5343,9 @@ static void QD3D12_CreateRTVsForWindow(QD3D12Window& w)
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
CreateTextureMsaaSrv(w.emissiveMsaaBuffers[i].Get(), QD3D12_EmissiveFormat, w.emissiveMsaaSrvIndex[i], w.emissiveMsaaSrvCpu[i], w.emissiveMsaaSrvGpu[i]);
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
CreateTextureMsaaSrv(w.specularMsaaBuffers[i].Get(), QD3D12_SpecularAlbedoFormat, w.specularMsaaSrvIndex[i], w.specularMsaaSrvCpu[i], w.specularMsaaSrvGpu[i]);
}
}
@@ -5502,7 +5667,7 @@ static ComPtr<ID3DBlob> CompileShaderVariant(const char* entry, const char* targ
static void QD3D12_CreatePostRootSignature()
{
D3D12_DESCRIPTOR_RANGE ranges[6]{};
D3D12_DESCRIPTOR_RANGE ranges[7]{};
for (UINT i = 0; i < _countof(ranges); ++i)
{
ranges[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
@@ -5512,7 +5677,7 @@ static void QD3D12_CreatePostRootSignature()
ranges[i].OffsetInDescriptorsFromTableStart = 0;
}
D3D12_ROOT_PARAMETER params[6]{};
D3D12_ROOT_PARAMETER params[7]{};
for (UINT i = 0; i < _countof(params); ++i)
{
params[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
@@ -5669,7 +5834,7 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildPSODesc(
d.PrimitiveTopologyType = topoType;
d.NumRenderTargets = nativeColorOnly ? 1u : 5u;
d.NumRenderTargets = nativeColorOnly ? 1u : 6u;
d.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
if (!nativeColorOnly)
{
@@ -5677,6 +5842,7 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildPSODesc(
d.RTVFormats[2] = DXGI_FORMAT_R16G16B16A16_FLOAT;
d.RTVFormats[3] = QD3D12_VelocityFormat;
d.RTVFormats[4] = QD3D12_EmissiveFormat;
d.RTVFormats[5] = QD3D12_SpecularAlbedoFormat;
}
d.DSVFormat = QD3D12_DepthDsvFormat;
@@ -5695,12 +5861,13 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildPSODesc(
d.BlendState.RenderTarget[2].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
d.BlendState.RenderTarget[3].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
d.BlendState.RenderTarget[4].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
d.BlendState.RenderTarget[5].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
}
d.BlendState.AlphaToCoverageEnable = FALSE;
d.BlendState.IndependentBlendEnable = nativeColorOnly ? FALSE : TRUE;
for (int i = 0; i < (nativeColorOnly ? 1 : 5); ++i)
for (int i = 0; i < (nativeColorOnly ? 1 : 6); ++i)
{
auto& rt = d.BlendState.RenderTarget[i];
rt.BlendEnable = FALSE;
@@ -5808,17 +5975,18 @@ static void QD3D12_CreatePSOs()
gbufferResolveDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
gbufferResolveDesc.SampleDesc.Count = 1;
gbufferResolveDesc.SampleMask = UINT_MAX;
gbufferResolveDesc.NumRenderTargets = 4;
gbufferResolveDesc.NumRenderTargets = 5;
gbufferResolveDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_FLOAT;
gbufferResolveDesc.RTVFormats[1] = DXGI_FORMAT_R16G16B16A16_FLOAT;
gbufferResolveDesc.RTVFormats[2] = QD3D12_VelocityFormat;
gbufferResolveDesc.RTVFormats[3] = QD3D12_EmissiveFormat;
gbufferResolveDesc.RTVFormats[4] = QD3D12_SpecularAlbedoFormat;
gbufferResolveDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
gbufferResolveDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
gbufferResolveDesc.RasterizerState.DepthClipEnable = TRUE;
gbufferResolveDesc.BlendState.AlphaToCoverageEnable = FALSE;
gbufferResolveDesc.BlendState.IndependentBlendEnable = FALSE;
for (UINT rt = 0; rt < 4; ++rt)
for (UINT rt = 0; rt < 5; ++rt)
{
gbufferResolveDesc.BlendState.RenderTarget[rt].BlendEnable = FALSE;
gbufferResolveDesc.BlendState.RenderTarget[rt].LogicOpEnable = FALSE;
@@ -5937,7 +6105,7 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildARBPSODesc(
d.InputLayout.NumElements = _countof(kGLVertexInputLayoutARB);
d.PrimitiveTopologyType = topoType;
d.NumRenderTargets = nativeColorOnly ? 1u : 5u;
d.NumRenderTargets = nativeColorOnly ? 1u : 6u;
d.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
if (!nativeColorOnly)
{
@@ -5945,6 +6113,7 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildARBPSODesc(
d.RTVFormats[2] = DXGI_FORMAT_R16G16B16A16_FLOAT;
d.RTVFormats[3] = QD3D12_VelocityFormat;
d.RTVFormats[4] = QD3D12_EmissiveFormat;
d.RTVFormats[5] = QD3D12_SpecularAlbedoFormat;
}
d.DSVFormat = QD3D12_DepthDsvFormat;
@@ -5959,7 +6128,7 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildARBPSODesc(
d.BlendState.AlphaToCoverageEnable = FALSE;
d.BlendState.IndependentBlendEnable = nativeColorOnly ? FALSE : TRUE;
for (int i = 0; i < (nativeColorOnly ? 1 : 5); ++i)
for (int i = 0; i < (nativeColorOnly ? 1 : 6); ++i)
{
auto& rt = d.BlendState.RenderTarget[i];
rt.BlendEnable = FALSE;
@@ -6334,10 +6503,12 @@ void QD3D12_BeginFrame()
const float positionClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float velocityClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float emissiveClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float specularClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
g_gl.cmdList->ClearRenderTargetView(CurrentNormalRTV(), normalClear, 0, nullptr);
g_gl.cmdList->ClearRenderTargetView(CurrentPositionRTV(), positionClear, 0, nullptr);
g_gl.cmdList->ClearRenderTargetView(CurrentVelocityRTV(), velocityClear, 0, nullptr);
g_gl.cmdList->ClearRenderTargetView(CurrentEmissiveRTV(), emissiveClear, 0, nullptr);
g_gl.cmdList->ClearRenderTargetView(CurrentSpecularRTV(), specularClear, 0, nullptr);
g_gl.frameOpen = true;
g_gl.frameOwner = &w;
@@ -6372,6 +6543,7 @@ void QD3D12_EndFrame()
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.normalBuffers[w.frameIndex].Get(), w.normalBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.positionBuffers[w.frameIndex].Get(), w.positionBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.velocityBuffers[w.frameIndex].Get(), w.velocityBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.specularBuffers[w.frameIndex].Get(), w.specularBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.depthBuffer.Get(), w.depthState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.backBuffers[w.frameIndex].Get(), w.backBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
@@ -7862,8 +8034,12 @@ static void FlushImmediate(GLenum mode, const GLVertex* src, size_t n)
const bool explicitGlowUnit = (!arbProgramsActive) &&
(g_gl.currentGlowMapTexture != 0) &&
(g_gl.boundTexture[unit] == g_gl.currentGlowMapTexture);
const bool taggedSpecularUnit = (!arbProgramsActive) && QD3D12_IsTextureTaggedSpecularMap(g_gl.boundTexture[unit]);
const bool explicitSpecularUnit = (!arbProgramsActive) &&
(g_gl.currentSpecularMapTexture != 0) &&
(g_gl.boundTexture[unit] == g_gl.currentSpecularMapTexture);
const bool wantsUnit = arbUnit || fixedColorUnit || taggedNormalUnit || explicitNormalUnit || taggedGlowUnit || explicitGlowUnit;
const bool wantsUnit = arbUnit || fixedColorUnit || taggedNormalUnit || explicitNormalUnit || taggedGlowUnit || explicitGlowUnit || taggedSpecularUnit || explicitSpecularUnit;
if (!wantsUnit)
continue;
@@ -7896,6 +8072,13 @@ static void FlushImmediate(GLenum mode, const GLVertex* src, size_t n)
UploadTexture(*glowMapTex);
}
TextureResource* specularMapTex = QD3D12_SelectSpecularMapTexture(boundTextures);
if (specularMapTex && specularMapTex != &g_gl.whiteTexture && !specularMapTex->gpuValid)
{
EnsureTextureResource(*specularMapTex);
UploadTexture(*specularMapTex);
}
TextureResource* tex0 = boundTextures[0];
TextureResource* tex1 = boundTextures[1];
@@ -8202,10 +8385,12 @@ static void QD3D12_FlushQueuedBatches()
D3D12_GPU_DESCRIPTOR_HANDLE lastTex1{};
D3D12_GPU_DESCRIPTOR_HANDLE lastNormalMap{};
D3D12_GPU_DESCRIPTOR_HANDLE lastGlowMap{};
D3D12_GPU_DESCRIPTOR_HANDLE lastSpecularMap{};
bool haveLastTex0 = false;
bool haveLastTex1 = false;
bool haveLastNormalMap = false;
bool haveLastGlowMap = false;
bool haveLastSpecularMap = false;
D3D12_PRIMITIVE_TOPOLOGY lastTopo = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
for (size_t i = 0; i < g_gl.queuedBatches.size(); ++i)
@@ -8232,6 +8417,7 @@ static void QD3D12_FlushQueuedBatches()
haveLastTex1 = false;
haveLastNormalMap = false;
haveLastGlowMap = false;
haveLastSpecularMap = false;
lastTopo = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
}
@@ -8300,6 +8486,10 @@ static void QD3D12_FlushQueuedBatches()
dc->_motionPad[1] = batch.key.normalMapStrength;
dc->_motionPad[2] = batch.key.normalMapYSign;
dc->_motionPad[3] = (batch.key.useGlowMap > 0.5f) ? batch.key.glowMapStrength : 0.0f;
dc->materialMapPad[0] = batch.key.useSpecularMap;
dc->materialMapPad[1] = batch.key.specularMapStrength;
dc->materialMapPad[2] = 0.0f;
dc->materialMapPad[3] = 0.0f;
if (batch.key.useARBPrograms)
{
@@ -8356,6 +8546,7 @@ static void QD3D12_FlushQueuedBatches()
haveLastTex1 = false;
haveLastNormalMap = false;
haveLastGlowMap = false;
haveLastSpecularMap = false;
}
else
{
@@ -8404,6 +8595,18 @@ static void QD3D12_FlushQueuedBatches()
lastGlowMap = glowMapGpu;
haveLastGlowMap = true;
}
UINT specularSrvIndex = batch.key.specularMapSrvIndex;
if (specularSrvIndex == UINT_MAX)
specularSrvIndex = g_gl.whiteTexture.srvIndex;
D3D12_GPU_DESCRIPTOR_HANDLE specularMapGpu = QD3D12_SrvGpu(specularSrvIndex);
if (!haveLastSpecularMap || specularMapGpu.ptr != lastSpecularMap.ptr)
{
g_gl.cmdList->SetGraphicsRootDescriptorTable(5, specularMapGpu);
lastSpecularMap = specularMapGpu;
haveLastSpecularMap = true;
}
}
g_gl.cmdList->SetGraphicsRootConstantBufferView(0, cbAlloc.gpu);
@@ -8535,12 +8738,14 @@ void APIENTRY glClear(GLbitfield mask)
const float positionClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float velocityClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float emissiveClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const float specularClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
g_gl.cmdList->ClearRenderTargetView(CurrentRTV(), cc, 1, &clearRect);
g_gl.cmdList->ClearRenderTargetView(CurrentNormalRTV(), normalClear, 1, &clearRect);
g_gl.cmdList->ClearRenderTargetView(CurrentPositionRTV(), positionClear, 1, &clearRect);
g_gl.cmdList->ClearRenderTargetView(CurrentVelocityRTV(), velocityClear, 1, &clearRect);
g_gl.cmdList->ClearRenderTargetView(CurrentEmissiveRTV(), emissiveClear, 1, &clearRect);
g_gl.cmdList->ClearRenderTargetView(CurrentSpecularRTV(), specularClear, 1, &clearRect);
}
}
@@ -8890,6 +9095,9 @@ void APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures)
if (g_gl.currentGlowMapTexture == deadId)
g_gl.currentGlowMapTexture = 0;
if (g_gl.currentSpecularMapTexture == deadId)
g_gl.currentSpecularMapTexture = 0;
auto it = g_gl.textures.find(deadId);
if (it != g_gl.textures.end())
{
@@ -8996,6 +9204,49 @@ void APIENTRY glGlowMapStrengthf(GLfloat strength)
g_gl.currentGlowMapStrength = (strength < 0.0f) ? 0.0f : strength;
}
void APIENTRY glTagTextureSpecularMap(GLuint texture, GLboolean isSpecularMap)
{
if (texture == 0)
{
g_gl.lastError = GL_INVALID_VALUE;
return;
}
TextureResource& tex = QD3D12_EnsureTextureName(texture);
tex.isSpecularMap = (isSpecularMap != GL_FALSE);
}
void APIENTRY glTextureSpecularMap(GLuint texture, GLboolean isSpecularMap)
{
glTagTextureSpecularMap(texture, isSpecularMap);
}
void APIENTRY glBindSpecularMapTexture(GLuint texture)
{
if (texture != 0)
{
TextureResource& tex = QD3D12_EnsureTextureName(texture);
if ((tex.isNormalMap && !tex.isSpecularMap) || (tex.isGlowMap && !tex.isSpecularMap))
{
QD3D12_Log("glBindSpecularMapTexture(%u) ignored: texture is tagged as a different material map role.", texture);
g_gl.currentSpecularMapTexture = 0;
return;
}
}
g_gl.currentSpecularMapTexture = texture;
}
void APIENTRY glSpecularMapTexture(GLuint texture)
{
glBindSpecularMapTexture(texture);
}
void APIENTRY glSpecularMapStrengthf(GLfloat strength)
{
g_gl.currentSpecularMapStrength = (strength < 0.0f) ? 0.0f : strength;
}
void APIENTRY glRaytracingMaterialFlagsQD3D12(GLuint flags)
{
g_gl.currentRayMaterialFlags = QD3D12_ClampRayMaterialFlags((uint32_t)flags);
@@ -9136,6 +9387,10 @@ void APIENTRY glGetIntegerv(GLenum pname, GLint* params)
*params = (GLint)g_gl.currentGlowMapTexture;
break;
case GL_SPECULAR_MAP_BINDING_QD3D12:
*params = (GLint)g_gl.currentSpecularMapTexture;
break;
case GL_QD3D12_MATERIAL_FLAGS:
*params = (GLint)QD3D12_CurrentRayMaterialFlags();
break;
@@ -10138,10 +10393,14 @@ void QD3D12_ReleaseWindowSizeResources(QD3D12Window& w)
w.normalBuffers[i].Reset();
w.positionBuffers[i].Reset();
w.velocityBuffers[i].Reset();
w.emissiveBuffers[i].Reset();
w.specularBuffers[i].Reset();
w.sceneColorMsaaBuffers[i].Reset();
w.normalMsaaBuffers[i].Reset();
w.positionMsaaBuffers[i].Reset();
w.velocityMsaaBuffers[i].Reset();
w.emissiveMsaaBuffers[i].Reset();
w.specularMsaaBuffers[i].Reset();
w.slOutputBuffers[i].Reset();
w.sceneColorState[i] = D3D12_RESOURCE_STATE_COMMON;
@@ -10149,10 +10408,14 @@ void QD3D12_ReleaseWindowSizeResources(QD3D12Window& w)
w.normalBufferState[i] = D3D12_RESOURCE_STATE_COMMON;
w.positionBufferState[i] = D3D12_RESOURCE_STATE_COMMON;
w.velocityBufferState[i] = D3D12_RESOURCE_STATE_COMMON;
w.emissiveBufferState[i] = D3D12_RESOURCE_STATE_COMMON;
w.specularBufferState[i] = D3D12_RESOURCE_STATE_COMMON;
w.sceneColorMsaaState[i] = D3D12_RESOURCE_STATE_COMMON;
w.normalMsaaState[i] = D3D12_RESOURCE_STATE_COMMON;
w.positionMsaaState[i] = D3D12_RESOURCE_STATE_COMMON;
w.velocityMsaaState[i] = D3D12_RESOURCE_STATE_COMMON;
w.emissiveMsaaState[i] = D3D12_RESOURCE_STATE_COMMON;
w.specularMsaaState[i] = D3D12_RESOURCE_STATE_COMMON;
w.slOutputState[i] = D3D12_RESOURCE_STATE_COMMON;
}
@@ -11700,6 +11963,11 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
{ "glBindGlowMapTexture", (PROC)glBindGlowMapTexture },
{ "glGlowMapTexture", (PROC)glGlowMapTexture },
{ "glGlowMapStrengthf", (PROC)glGlowMapStrengthf },
{ "glTagTextureSpecularMap", (PROC)glTagTextureSpecularMap },
{ "glTextureSpecularMap", (PROC)glTextureSpecularMap },
{ "glBindSpecularMapTexture", (PROC)glBindSpecularMapTexture },
{ "glSpecularMapTexture", (PROC)glSpecularMapTexture },
{ "glSpecularMapStrengthf", (PROC)glSpecularMapStrengthf },
{ "glGlassMaterialQD3D12", (PROC)glGlassMaterialQD3D12 },
{ "glMaterialGlassQD3D12", (PROC)glMaterialGlassQD3D12 },
{ "glRaytracingMaterialFlagsQD3D12", (PROC)glRaytracingMaterialFlagsQD3D12 },
@@ -11959,8 +12227,8 @@ static void QD3D12_PointResolveMsaaGBufferToSingleSample(QD3D12Window& w)
const UINT frame = w.frameIndex;
if (!w.depthMsaaBuffer ||
!w.normalMsaaBuffers[frame] || !w.positionMsaaBuffers[frame] || !w.velocityMsaaBuffers[frame] || !w.emissiveMsaaBuffers[frame] ||
!w.normalBuffers[frame] || !w.positionBuffers[frame] || !w.velocityBuffers[frame] || !w.emissiveBuffers[frame])
!w.normalMsaaBuffers[frame] || !w.positionMsaaBuffers[frame] || !w.velocityMsaaBuffers[frame] || !w.emissiveMsaaBuffers[frame] || !w.specularMsaaBuffers[frame] ||
!w.normalBuffers[frame] || !w.positionBuffers[frame] || !w.velocityBuffers[frame] || !w.emissiveBuffers[frame] || !w.specularBuffers[frame])
{
return;
}
@@ -11970,18 +12238,21 @@ static void QD3D12_PointResolveMsaaGBufferToSingleSample(QD3D12Window& w)
QD3D12_TransitionResource(cl, w.positionMsaaBuffers[frame].Get(), w.positionMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, w.velocityMsaaBuffers[frame].Get(), w.velocityMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, w.emissiveMsaaBuffers[frame].Get(), w.emissiveMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, w.specularMsaaBuffers[frame].Get(), w.specularMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, w.normalBuffers[frame].Get(), w.normalBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.positionBuffers[frame].Get(), w.positionBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.velocityBuffers[frame].Get(), w.velocityBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.emissiveBuffers[frame].Get(), w.emissiveBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.specularBuffers[frame].Get(), w.specularBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[4] =
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[5] =
{
CurrentResolvedNormalRTV(),
CurrentResolvedPositionRTV(),
CurrentResolvedVelocityRTV(),
CurrentResolvedEmissiveRTV()
CurrentResolvedEmissiveRTV(),
CurrentResolvedSpecularRTV()
};
D3D12_VIEWPORT viewport{};
@@ -12002,18 +12273,19 @@ static void QD3D12_PointResolveMsaaGBufferToSingleSample(QD3D12Window& w)
cl->SetDescriptorHeaps(_countof(heaps), heaps);
cl->SetGraphicsRootSignature(g_gl.postRootSig.Get());
cl->SetPipelineState(g_gl.postGBufferPointResolveMsaaPSO.Get());
cl->OMSetRenderTargets(4, rtvs, FALSE, nullptr);
cl->OMSetRenderTargets(5, rtvs, FALSE, nullptr);
cl->RSSetViewports(1, &viewport);
cl->RSSetScissorRects(1, &scissor);
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// t1..t5: depth + discontinuous G-buffer attributes. The shader uses
// t1..t6: depth + discontinuous G-buffer attributes. The shader uses
// Texture2DMS.Load(), selects a single depth-nearest sample, and never averages.
cl->SetGraphicsRootDescriptorTable(1, w.depthMsaaSrvGpu);
cl->SetGraphicsRootDescriptorTable(2, w.normalMsaaSrvGpu[frame]);
cl->SetGraphicsRootDescriptorTable(3, w.positionMsaaSrvGpu[frame]);
cl->SetGraphicsRootDescriptorTable(4, w.velocityMsaaSrvGpu[frame]);
cl->SetGraphicsRootDescriptorTable(5, w.emissiveMsaaSrvGpu[frame]);
cl->SetGraphicsRootDescriptorTable(6, w.specularMsaaSrvGpu[frame]);
cl->DrawInstanced(3, 1, 0, 0);
}
@@ -12090,6 +12362,7 @@ static void QD3D12_BindLowResSceneTargets(QD3D12Window& w)
QD3D12_TransitionResource(cl, w.positionMsaaBuffers[w.frameIndex].Get(), w.positionMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.velocityMsaaBuffers[w.frameIndex].Get(), w.velocityMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.emissiveMsaaBuffers[w.frameIndex].Get(), w.emissiveMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.specularMsaaBuffers[w.frameIndex].Get(), w.specularMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.depthMsaaBuffer.Get(), w.depthMsaaState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
else
@@ -12099,19 +12372,21 @@ static void QD3D12_BindLowResSceneTargets(QD3D12Window& w)
QD3D12_TransitionResource(cl, w.positionBuffers[w.frameIndex].Get(), w.positionBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.velocityBuffers[w.frameIndex].Get(), w.velocityBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.emissiveBuffers[w.frameIndex].Get(), w.emissiveBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.specularBuffers[w.frameIndex].Get(), w.specularBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, w.depthBuffer.Get(), w.depthState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[5] =
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[6] =
{
CurrentRTV(),
CurrentNormalRTV(),
CurrentPositionRTV(),
CurrentVelocityRTV(),
CurrentEmissiveRTV()
CurrentEmissiveRTV(),
CurrentSpecularRTV()
};
D3D12_CPU_DESCRIPTOR_HANDLE dsv = CurrentActiveSceneDepthDSV();
cl->OMSetRenderTargets(5, rtvs, FALSE, &dsv);
cl->OMSetRenderTargets(6, rtvs, FALSE, &dsv);
cl->RSSetViewports(1, &w.viewport);
cl->RSSetScissorRects(1, &w.scissor);
}
@@ -12206,6 +12481,7 @@ static void QD3D12_ResolveSceneToOutputAndEnterNativePhase(QD3D12Window& w)
QD3D12_TransitionResource(cl, w.sceneColorBuffers[w.frameIndex].Get(), w.sceneColorState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, w.velocityBuffers[w.frameIndex].Get(), w.velocityBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, w.specularBuffers[w.frameIndex].Get(), w.specularBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, w.depthBuffer.Get(), w.depthState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
if (useLightingUpscaleInput)
@@ -12271,9 +12547,10 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
ID3D12Resource* sceneNormal = window->normalBuffers[frameIndex].Get();
ID3D12Resource* scenePosition = window->positionBuffers[frameIndex].Get();
ID3D12Resource* sceneEmissive = window->emissiveBuffers[frameIndex].Get();
ID3D12Resource* sceneSpecular = window->specularBuffers[frameIndex].Get();
ID3D12Resource* sceneDepth = window->depthBuffer.Get();
if (!sceneColor || !sceneNormal || !scenePosition || !sceneEmissive || !sceneDepth)
if (!sceneColor || !sceneNormal || !scenePosition || !sceneEmissive || !sceneSpecular || !sceneDepth)
return;
QD3D12_TransitionResource(
@@ -12300,6 +12577,12 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
window->emissiveBufferState[frameIndex],
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(
cl,
sceneSpecular,
window->specularBufferState[frameIndex],
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(
cl,
sceneDepth,
@@ -12342,6 +12625,7 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
useDLSSRayReconstruction ? 0 : 1,
useDLSSRayReconstruction ? 0.0f : 1.0f);
glRaytracingLightingSetEmissiveInput(sceneEmissive, QD3D12_EmissiveFormat);
glRaytracingLightingSetSpecularInput(sceneSpecular, QD3D12_SpecularAlbedoFormat);
glRaytracingLightingPassDesc_t pass = {};
pass.albedoTexture = sceneColor;
@@ -12371,6 +12655,7 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
QD3D12_TransitionResource(cl, window->positionMsaaBuffers[frameIndex].Get(), window->positionMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->velocityMsaaBuffers[frameIndex].Get(), window->velocityMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->emissiveMsaaBuffers[frameIndex].Get(), window->emissiveMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->specularMsaaBuffers[frameIndex].Get(), window->specularMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->depthMsaaBuffer.Get(), window->depthMsaaState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
else
@@ -12399,6 +12684,12 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
window->emissiveBufferState[frameIndex],
D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(
cl,
sceneSpecular,
window->specularBufferState[frameIndex],
D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(
cl,
sceneDepth,
+6
View File
@@ -2222,6 +2222,12 @@ void APIENTRY glNormalMapTexture(GLuint texture); // alia
void APIENTRY glNormalMapStrengthf(GLfloat strength); // default 1.0
void APIENTRY glNormalMapYSignf(GLfloat sign); // default +1, pass -1 to flip green/Y
void APIENTRY glTagTextureSpecularMap(GLuint texture, GLboolean isSpecularMap);
void APIENTRY glTextureSpecularMap(GLuint texture, GLboolean isSpecularMap);
void APIENTRY glBindSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapStrengthf(GLfloat strength);
void glUpdateTopLevelAceelStructure(
glRaytracingSceneHandle_t scene,
uint32_t mesh,
+14
View File
@@ -1900,6 +1900,20 @@ idImage* idMaterial::GetBumpImage(void) const {
return GetEditorImage();
}
/*
===================
idMaterial::GetSpecImage
===================
*/
idImage* idMaterial::GetSpecImage(void) const {
for (int i = 0; i < numStages; i++) {
if (stages[i].lighting == SL_SPECULAR && stages[i].texture.image) {
return stages[i].texture.image;
}
}
return globalImages->blackImage;
}
/*
===================
idMaterial::GetGlowImage
+1
View File
@@ -507,6 +507,7 @@ public:
// jmarshall
idImage* GetDiffuseImage(void) const;
idImage* GetBumpImage(void) const;
idImage* GetSpecImage(void) const;
idImage* GetGlowImage(void) const;
bool IsSky(void) const;
// jmarshall end
+20 -6
View File
@@ -442,10 +442,10 @@ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) {
bool drawSolid = false;
if ( shader->Coverage() == MC_OPAQUE ) {
//if ( shader->Coverage() == MC_OPAQUE ) {
drawSolid = true;
}
//}
#if 0
// we may have multiple alpha tested stages
if ( shader->Coverage() == MC_PERFORATED ) {
// if the only alpha tested stages are condition register omitted,
@@ -497,7 +497,7 @@ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) {
drawSolid = true;
}
}
#endif
// draw the entire surface solid
// draw the entire surface solid
if (drawSolid && !shader->IsSky()) {
@@ -512,10 +512,15 @@ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) {
shader->GetBumpImage()->Bind();
glBindNormalMapTexture(shader->GetBumpImage()->texnum);
GL_SelectTexture(2);
glEnable(GL_TEXTURE_2D);
shader->GetSpecImage()->Bind();
glBindSpecularMapTexture(shader->GetSpecImage()->texnum);
idImage* glowMapImage = shader->GetGlowImage();
if (glowMapImage)
{
GL_SelectTexture(2);
GL_SelectTexture(3);
glEnable(GL_TEXTURE_2D);
glowMapImage->Bind();
glBindGlowMapTexture(glowMapImage->texnum);
@@ -539,11 +544,15 @@ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) {
if (glowMapImage)
{
GL_SelectTexture(2);
GL_SelectTexture(3);
glBindGlowMapTexture(0);
globalImages->BindNull();
}
GL_SelectTexture(2);
glBindSpecularMapTexture(0);
globalImages->BindNull();
GL_SelectTexture(1);
glBindNormalMapTexture(0);
globalImages->BindNull();
@@ -940,6 +949,11 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
continue;
}
// check the stage enable condition
if (regs[pStage->conditionRegister] == 0) {
continue;
}
// select the vertex color source
if ( pStage->vertexColor == SVC_IGNORE ) {
glColor4fv( color );