in Src/EffectFactory.cpp [111:466]
std::shared_ptr<IEffect> EffectFactory::Impl::CreateEffect(
const EffectInfo& info,
const EffectPipelineStateDescription& opaquePipelineState,
const EffectPipelineStateDescription& alphaPipelineState,
const D3D12_INPUT_LAYOUT_DESC& inputLayoutDesc,
int textureDescriptorOffset,
int samplerDescriptorOffset)
{
// If textures are required, make sure we have a descriptor heap
if (!mTextureDescriptors && (info.diffuseTextureIndex != -1 || info.specularTextureIndex != -1 || info.normalTextureIndex != -1 || info.emissiveTextureIndex != -1))
{
DebugTrace("ERROR: EffectFactory created without texture descriptor heap with texture index set (diffuse %d, specular %d, normal %d, emissive %d)!\n",
info.diffuseTextureIndex, info.specularTextureIndex, info.normalTextureIndex, info.emissiveTextureIndex);
throw std::runtime_error("EffectFactory");
}
if (!mSamplerDescriptors && (info.samplerIndex != -1 || info.samplerIndex2 != -1))
{
DebugTrace("ERROR: EffectFactory created without sampler descriptor heap with sampler index set (samplerIndex %d, samplerIndex2 %d)!\n",
info.samplerIndex, info.samplerIndex2);
throw std::runtime_error("EffectFactory");
}
// If we have descriptors, make sure we have both texture and sampler descriptors
if ((mTextureDescriptors == nullptr) != (mSamplerDescriptors == nullptr))
{
DebugTrace("ERROR: A texture or sampler descriptor heap was provided, but both are required.\n");
throw std::runtime_error("EffectFactory");
}
// Validate the we have either both texture and sampler descriptors, or neither
if ((info.diffuseTextureIndex == -1) != (info.samplerIndex == -1))
{
DebugTrace("ERROR: Material provides either a texture or sampler, but both are required.\n");
throw std::runtime_error("EffectFactory");
}
int diffuseTextureIndex = (info.diffuseTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.diffuseTextureIndex + textureDescriptorOffset : -1;
int specularTextureIndex = (info.specularTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.specularTextureIndex + textureDescriptorOffset : -1;
int emissiveTextureIndex = (info.emissiveTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.emissiveTextureIndex + textureDescriptorOffset : -1;
int normalTextureIndex = (info.normalTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.normalTextureIndex + textureDescriptorOffset : -1;
int samplerIndex = (info.samplerIndex != -1 && mSamplerDescriptors != nullptr) ? info.samplerIndex + samplerDescriptorOffset : -1;
int samplerIndex2 = (info.samplerIndex2 != -1 && mSamplerDescriptors != nullptr) ? info.samplerIndex2 + samplerDescriptorOffset : -1;
// Modify base pipeline state
EffectPipelineStateDescription derivedPSD = (info.alphaValue < 1.0f) ? alphaPipelineState : opaquePipelineState;
derivedPSD.inputLayout = inputLayoutDesc;
std::wstring cacheName;
if (info.enableSkinning)
{
int effectflags = (mEnablePerPixelLighting) ? EffectFlags::PerPixelLighting : EffectFlags::Lighting;
if (mEnableFog)
{
effectflags |= EffectFlags::Fog;
}
if (info.biasedVertexNormals)
{
effectflags |= EffectFlags::BiasedVertexNormals;
}
if (info.enableNormalMaps && mUseNormalMapEffect)
{
// SkinnedNormalMapEffect
if (specularTextureIndex != -1)
{
effectflags |= EffectFlags::Specular;
}
if (mSharing && !info.name.empty())
{
uint32_t hash = derivedPSD.ComputeHash();
cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);
auto it = mEffectCacheNormalMapSkinned.find(cacheName);
if (mSharing && it != mEffectCacheNormalMapSkinned.end())
{
return it->second;
}
}
auto effect = std::make_shared<SkinnedNormalMapEffect>(mDevice.Get(), effectflags, derivedPSD);
SetMaterialProperties(effect.get(), info);
if (diffuseTextureIndex != -1)
{
effect->SetTexture(
mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),
mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));
}
if (specularTextureIndex != -1)
{
effect->SetSpecularTexture(mTextureDescriptors->GetGpuHandle(static_cast<size_t>(specularTextureIndex)));
}
if (normalTextureIndex != -1)
{
effect->SetNormalTexture(mTextureDescriptors->GetGpuHandle(static_cast<size_t>(normalTextureIndex)));
}
if (mSharing && !info.name.empty())
{
std::lock_guard<std::mutex> lock(mutex);
EffectCache::value_type v(cacheName, effect);
mEffectCacheNormalMapSkinned.insert(v);
}
return std::move(effect);
}
else
{
// SkinnedEffect
if (mSharing && !info.name.empty())
{
uint32_t hash = derivedPSD.ComputeHash();
cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);
auto it = mEffectCacheSkinning.find(cacheName);
if (mSharing && it != mEffectCacheSkinning.end())
{
return it->second;
}
}
auto effect = std::make_shared<SkinnedEffect>(mDevice.Get(), effectflags, derivedPSD);
SetMaterialProperties(effect.get(), info);
if (diffuseTextureIndex != -1)
{
effect->SetTexture(
mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),
mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));
}
if (mSharing && !info.name.empty())
{
std::lock_guard<std::mutex> lock(mutex);
EffectCache::value_type v(cacheName, effect);
mEffectCacheSkinning.insert(v);
}
return std::move(effect);
}
}
else if (info.enableDualTexture)
{
// DualTextureEffect
int effectflags = EffectFlags::None;
if (mEnableFog)
{
effectflags |= EffectFlags::Fog;
}
if (mSharing && !info.name.empty())
{
uint32_t hash = derivedPSD.ComputeHash();
cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);
auto it = mEffectCacheDualTexture.find(cacheName);
if (mSharing && it != mEffectCacheDualTexture.end())
{
return it->second;
}
}
if (info.perVertexColor)
{
effectflags |= EffectFlags::VertexColor;
}
auto effect = std::make_shared<DualTextureEffect>(mDevice.Get(), effectflags, derivedPSD);
// Dual texture effect doesn't support lighting (usually it's lightmaps)
effect->SetAlpha(info.alphaValue);
XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
effect->SetDiffuseColor(color);
if (diffuseTextureIndex != -1)
{
effect->SetTexture(
mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),
mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));
}
if (emissiveTextureIndex != -1)
{
if (samplerIndex2 == -1)
{
DebugTrace("ERROR: Dual-texture requires a second sampler (emissive %d)\n", emissiveTextureIndex);
throw std::runtime_error("EffectFactory");
}
effect->SetTexture2(
mTextureDescriptors->GetGpuHandle(static_cast<size_t>(emissiveTextureIndex)),
mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex2)));
}
else if (specularTextureIndex != -1)
{
// If there's no emissive texture specified, use the specular texture as the second texture
if (samplerIndex2 == -1)
{
DebugTrace("ERROR: Dual-texture requires a second sampler (specular %d)\n", specularTextureIndex);
throw std::runtime_error("EffectFactory");
}
effect->SetTexture2(
mTextureDescriptors->GetGpuHandle(static_cast<size_t>(specularTextureIndex)),
mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex2)));
}
if (mSharing && !info.name.empty())
{
std::lock_guard<std::mutex> lock(mutex);
EffectCache::value_type v(cacheName, effect);
mEffectCacheDualTexture.insert(v);
}
return std::move(effect);
}
else if (info.enableNormalMaps && mUseNormalMapEffect)
{
// NormalMapEffect
int effectflags = EffectFlags::None;
if (mEnableFog)
{
effectflags |= EffectFlags::Fog;
}
if (mEnableInstancing)
{
effectflags |= EffectFlags::Instancing;
}
if (info.perVertexColor)
{
effectflags |= EffectFlags::VertexColor;
}
if (info.biasedVertexNormals)
{
effectflags |= EffectFlags::BiasedVertexNormals;
}
if (specularTextureIndex != -1)
{
effectflags |= EffectFlags::Specular;
}
if (mSharing && !info.name.empty())
{
uint32_t hash = derivedPSD.ComputeHash();
cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);
auto it = mEffectCacheNormalMap.find(cacheName);
if (mSharing && it != mEffectCacheNormalMap.end())
{
return it->second;
}
}
auto effect = std::make_shared<NormalMapEffect>(mDevice.Get(), effectflags, derivedPSD);
SetMaterialProperties(effect.get(), info);
if (diffuseTextureIndex != -1)
{
effect->SetTexture(
mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),
mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));
}
if (specularTextureIndex != -1)
{
effect->SetSpecularTexture(mTextureDescriptors->GetGpuHandle(static_cast<size_t>(specularTextureIndex)));
}
if (normalTextureIndex != -1)
{
effect->SetNormalTexture(mTextureDescriptors->GetGpuHandle(static_cast<size_t>(normalTextureIndex)));
}
if (mSharing && !info.name.empty())
{
std::lock_guard<std::mutex> lock(mutex);
EffectCache::value_type v(cacheName, effect);
mEffectCacheNormalMap.insert(v);
}
return std::move(effect);
}
else
{
// set effect flags for creation
int effectflags = (mEnablePerPixelLighting) ? EffectFlags::PerPixelLighting : EffectFlags::Lighting;
if (mEnableFog)
{
effectflags |= EffectFlags::Fog;
}
if (info.perVertexColor)
{
effectflags |= EffectFlags::VertexColor;
}
if (diffuseTextureIndex != -1)
{
effectflags |= EffectFlags::Texture;
}
if (info.biasedVertexNormals)
{
effectflags |= EffectFlags::BiasedVertexNormals;
}
// BasicEffect
if (mSharing && !info.name.empty())
{
uint32_t hash = derivedPSD.ComputeHash();
cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);
auto it = mEffectCache.find(cacheName);
if (mSharing && it != mEffectCache.end())
{
return it->second;
}
}
auto effect = std::make_shared<BasicEffect>(mDevice.Get(), effectflags, derivedPSD);
SetMaterialProperties(effect.get(), info);
if (diffuseTextureIndex != -1)
{
effect->SetTexture(
mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),
mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));
}
if (mSharing && !info.name.empty())
{
std::lock_guard<std::mutex> lock(mutex);
EffectCache::value_type v(cacheName, effect);
mEffectCache.insert(v);
}
return std::move(effect);
}
}