template project, first version
This commit is contained in:
521
DirectXTK/Src/EffectFactory.cpp
Normal file
521
DirectXTK/Src/EffectFactory.cpp
Normal file
@@ -0,0 +1,521 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: EffectFactory.cpp
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
// PARTICULAR PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248929
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#include "pch.h"
|
||||
#include "Effects.h"
|
||||
#include "DemandCreate.h"
|
||||
#include "SharedResourcePool.h"
|
||||
|
||||
#include "DDSTextureLoader.h"
|
||||
#include "WICTextureLoader.h"
|
||||
|
||||
using namespace DirectX;
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
// Internal EffectFactory implementation class. Only one of these helpers is allocated
|
||||
// per D3D device, even if there are multiple public facing EffectFactory instances.
|
||||
class EffectFactory::Impl
|
||||
{
|
||||
public:
|
||||
Impl(_In_ ID3D11Device* device)
|
||||
: mPath{},
|
||||
device(device),
|
||||
mSharing(true),
|
||||
mUseNormalMapEffect(true),
|
||||
mForceSRGB(false)
|
||||
{}
|
||||
|
||||
std::shared_ptr<IEffect> CreateEffect( _In_ IEffectFactory* factory, _In_ const IEffectFactory::EffectInfo& info, _In_opt_ ID3D11DeviceContext* deviceContext );
|
||||
void CreateTexture( _In_z_ const wchar_t* texture, _In_opt_ ID3D11DeviceContext* deviceContext, _Outptr_ ID3D11ShaderResourceView** textureView );
|
||||
|
||||
void ReleaseCache();
|
||||
void SetSharing( bool enabled ) { mSharing = enabled; }
|
||||
void EnableNormalMapEffect( bool enabled ) { mUseNormalMapEffect = enabled; }
|
||||
void EnableForceSRGB(bool forceSRGB) { mForceSRGB = forceSRGB; }
|
||||
|
||||
static SharedResourcePool<ID3D11Device*, Impl> instancePool;
|
||||
|
||||
wchar_t mPath[MAX_PATH];
|
||||
|
||||
private:
|
||||
ComPtr<ID3D11Device> device;
|
||||
|
||||
typedef std::map< std::wstring, std::shared_ptr<IEffect> > EffectCache;
|
||||
typedef std::map< std::wstring, ComPtr<ID3D11ShaderResourceView> > TextureCache;
|
||||
|
||||
EffectCache mEffectCache;
|
||||
EffectCache mEffectCacheSkinning;
|
||||
EffectCache mEffectCacheDualTexture;
|
||||
EffectCache mEffectNormalMap;
|
||||
TextureCache mTextureCache;
|
||||
|
||||
bool mSharing;
|
||||
bool mUseNormalMapEffect;
|
||||
bool mForceSRGB;
|
||||
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
|
||||
// Global instance pool.
|
||||
SharedResourcePool<ID3D11Device*, EffectFactory::Impl> EffectFactory::Impl::instancePool;
|
||||
|
||||
|
||||
_Use_decl_annotations_
|
||||
std::shared_ptr<IEffect> EffectFactory::Impl::CreateEffect(IEffectFactory* factory, const IEffectFactory::EffectInfo& info, ID3D11DeviceContext* deviceContext)
|
||||
{
|
||||
if (info.enableSkinning)
|
||||
{
|
||||
// SkinnedEffect
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
auto it = mEffectCacheSkinning.find(info.name);
|
||||
if (mSharing && it != mEffectCacheSkinning.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
auto effect = std::make_shared<SkinnedEffect>(device.Get());
|
||||
|
||||
effect->EnableDefaultLighting();
|
||||
|
||||
effect->SetAlpha(info.alpha);
|
||||
|
||||
// Skinned Effect does not have an ambient material color, or per-vertex color support
|
||||
|
||||
XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
|
||||
effect->SetDiffuseColor(color);
|
||||
|
||||
if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)
|
||||
{
|
||||
color = XMLoadFloat3(&info.specularColor);
|
||||
effect->SetSpecularColor(color);
|
||||
effect->SetSpecularPower(info.specularPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
effect->DisableSpecular();
|
||||
}
|
||||
|
||||
if (info.emissiveColor.x != 0 || info.emissiveColor.y != 0 || info.emissiveColor.z != 0)
|
||||
{
|
||||
color = XMLoadFloat3(&info.emissiveColor);
|
||||
effect->SetEmissiveColor(color);
|
||||
}
|
||||
|
||||
if (info.diffuseTexture && *info.diffuseTexture)
|
||||
{
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
|
||||
factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());
|
||||
|
||||
effect->SetTexture(srv.Get());
|
||||
}
|
||||
|
||||
if (info.biasedVertexNormals)
|
||||
{
|
||||
effect->SetBiasedVertexNormals(true);
|
||||
}
|
||||
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
mEffectCacheSkinning.insert(EffectCache::value_type(info.name, effect));
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
else if (info.enableDualTexture)
|
||||
{
|
||||
// DualTextureEffect
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
auto it = mEffectCacheDualTexture.find(info.name);
|
||||
if (mSharing && it != mEffectCacheDualTexture.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
auto effect = std::make_shared<DualTextureEffect>(device.Get());
|
||||
|
||||
// Dual texture effect doesn't support lighting (usually it's lightmaps)
|
||||
|
||||
effect->SetAlpha(info.alpha);
|
||||
|
||||
if (info.perVertexColor)
|
||||
{
|
||||
effect->SetVertexColorEnabled(true);
|
||||
}
|
||||
|
||||
XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
|
||||
effect->SetDiffuseColor(color);
|
||||
|
||||
if (info.diffuseTexture && *info.diffuseTexture)
|
||||
{
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
|
||||
factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());
|
||||
|
||||
effect->SetTexture(srv.Get());
|
||||
}
|
||||
|
||||
if (info.specularTexture && *info.specularTexture)
|
||||
{
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
|
||||
factory->CreateTexture(info.specularTexture, deviceContext, srv.GetAddressOf());
|
||||
|
||||
effect->SetTexture2(srv.Get());
|
||||
}
|
||||
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
mEffectCacheDualTexture.insert(EffectCache::value_type(info.name, effect));
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
else if (info.enableNormalMaps && mUseNormalMapEffect)
|
||||
{
|
||||
// NormalMapEffect
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
auto it = mEffectNormalMap.find(info.name);
|
||||
if (mSharing && it != mEffectNormalMap.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
auto effect = std::make_shared<NormalMapEffect>(device.Get());
|
||||
|
||||
effect->EnableDefaultLighting();
|
||||
|
||||
effect->SetAlpha(info.alpha);
|
||||
|
||||
if (info.perVertexColor)
|
||||
{
|
||||
effect->SetVertexColorEnabled(true);
|
||||
}
|
||||
|
||||
// NormalMap Effect does not have an ambient material color
|
||||
|
||||
XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
|
||||
effect->SetDiffuseColor(color);
|
||||
|
||||
if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)
|
||||
{
|
||||
color = XMLoadFloat3(&info.specularColor);
|
||||
effect->SetSpecularColor(color);
|
||||
effect->SetSpecularPower(info.specularPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
effect->DisableSpecular();
|
||||
}
|
||||
|
||||
if (info.emissiveColor.x != 0 || info.emissiveColor.y != 0 || info.emissiveColor.z != 0)
|
||||
{
|
||||
color = XMLoadFloat3(&info.emissiveColor);
|
||||
effect->SetEmissiveColor(color);
|
||||
}
|
||||
|
||||
if (info.diffuseTexture && *info.diffuseTexture)
|
||||
{
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
|
||||
factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());
|
||||
|
||||
effect->SetTexture(srv.Get());
|
||||
}
|
||||
|
||||
if (info.specularTexture && *info.specularTexture)
|
||||
{
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
|
||||
factory->CreateTexture(info.specularTexture, deviceContext, srv.GetAddressOf());
|
||||
|
||||
effect->SetSpecularTexture(srv.Get());
|
||||
}
|
||||
|
||||
if (info.normalTexture && *info.normalTexture)
|
||||
{
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
|
||||
factory->CreateTexture(info.normalTexture, deviceContext, srv.GetAddressOf());
|
||||
|
||||
effect->SetNormalTexture(srv.Get());
|
||||
}
|
||||
|
||||
if (info.biasedVertexNormals)
|
||||
{
|
||||
effect->SetBiasedVertexNormalsAndTangents(true);
|
||||
}
|
||||
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
mEffectNormalMap.insert(EffectCache::value_type(info.name, effect));
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
else
|
||||
{
|
||||
// BasicEffect
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
auto it = mEffectCache.find(info.name);
|
||||
if (mSharing && it != mEffectCache.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
auto effect = std::make_shared<BasicEffect>(device.Get());
|
||||
|
||||
effect->EnableDefaultLighting();
|
||||
effect->SetLightingEnabled(true);
|
||||
|
||||
effect->SetAlpha(info.alpha);
|
||||
|
||||
if (info.perVertexColor)
|
||||
{
|
||||
effect->SetVertexColorEnabled(true);
|
||||
}
|
||||
|
||||
// Basic Effect does not have an ambient material color
|
||||
|
||||
XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
|
||||
effect->SetDiffuseColor(color);
|
||||
|
||||
if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)
|
||||
{
|
||||
color = XMLoadFloat3(&info.specularColor);
|
||||
effect->SetSpecularColor(color);
|
||||
effect->SetSpecularPower(info.specularPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
effect->DisableSpecular();
|
||||
}
|
||||
|
||||
if (info.emissiveColor.x != 0 || info.emissiveColor.y != 0 || info.emissiveColor.z != 0)
|
||||
{
|
||||
color = XMLoadFloat3(&info.emissiveColor);
|
||||
effect->SetEmissiveColor(color);
|
||||
}
|
||||
|
||||
if (info.diffuseTexture && *info.diffuseTexture)
|
||||
{
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
|
||||
factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());
|
||||
|
||||
effect->SetTexture(srv.Get());
|
||||
effect->SetTextureEnabled(true);
|
||||
}
|
||||
|
||||
if (info.biasedVertexNormals)
|
||||
{
|
||||
effect->SetBiasedVertexNormals(true);
|
||||
}
|
||||
|
||||
if (mSharing && info.name && *info.name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
mEffectCache.insert(EffectCache::value_type(info.name, effect));
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
void EffectFactory::Impl::CreateTexture(const wchar_t* name, ID3D11DeviceContext* deviceContext, ID3D11ShaderResourceView** textureView)
|
||||
{
|
||||
if (!name || !textureView)
|
||||
throw std::exception("invalid arguments");
|
||||
|
||||
#if defined(_XBOX_ONE) && defined(_TITLE)
|
||||
UNREFERENCED_PARAMETER(deviceContext);
|
||||
#endif
|
||||
|
||||
auto it = mTextureCache.find(name);
|
||||
|
||||
if (mSharing && it != mTextureCache.end())
|
||||
{
|
||||
ID3D11ShaderResourceView* srv = it->second.Get();
|
||||
srv->AddRef();
|
||||
*textureView = srv;
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t fullName[MAX_PATH] = {};
|
||||
wcscpy_s(fullName, mPath);
|
||||
wcscat_s(fullName, name);
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA fileAttr = {};
|
||||
if (!GetFileAttributesExW(fullName, GetFileExInfoStandard, &fileAttr))
|
||||
{
|
||||
// Try Current Working Directory (CWD)
|
||||
wcscpy_s(fullName, name);
|
||||
if (!GetFileAttributesExW(fullName, GetFileExInfoStandard, &fileAttr))
|
||||
{
|
||||
DebugTrace("EffectFactory could not find texture file '%ls'\n", name);
|
||||
throw std::exception("CreateTexture");
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t ext[_MAX_EXT];
|
||||
_wsplitpath_s(name, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT);
|
||||
|
||||
if (_wcsicmp(ext, L".dds") == 0)
|
||||
{
|
||||
HRESULT hr = CreateDDSTextureFromFileEx(
|
||||
device.Get(), fullName, 0,
|
||||
D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0,
|
||||
mForceSRGB, nullptr, textureView);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DebugTrace("CreateDDSTextureFromFile failed (%08X) for '%ls'\n", hr, fullName);
|
||||
throw std::exception("CreateDDSTextureFromFile");
|
||||
}
|
||||
}
|
||||
#if !defined(_XBOX_ONE) || !defined(_TITLE)
|
||||
else if (deviceContext)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
HRESULT hr = CreateWICTextureFromFileEx(
|
||||
device.Get(), deviceContext, fullName, 0,
|
||||
D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0,
|
||||
mForceSRGB ? WIC_LOADER_FORCE_SRGB : WIC_LOADER_DEFAULT, nullptr, textureView);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DebugTrace("CreateWICTextureFromFile failed (%08X) for '%ls'\n", hr, fullName);
|
||||
throw std::exception("CreateWICTextureFromFile");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
HRESULT hr = CreateWICTextureFromFileEx(
|
||||
device.Get(), fullName, 0,
|
||||
D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0,
|
||||
mForceSRGB ? WIC_LOADER_FORCE_SRGB : WIC_LOADER_DEFAULT, nullptr, textureView);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DebugTrace("CreateWICTextureFromFile failed (%08X) for '%ls'\n", hr, fullName);
|
||||
throw std::exception("CreateWICTextureFromFile");
|
||||
}
|
||||
}
|
||||
|
||||
if (mSharing && *name && it == mTextureCache.end())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
mTextureCache.insert(TextureCache::value_type(name, *textureView));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EffectFactory::Impl::ReleaseCache()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
mEffectCache.clear();
|
||||
mEffectCacheSkinning.clear();
|
||||
mEffectCacheDualTexture.clear();
|
||||
mEffectNormalMap.clear();
|
||||
mTextureCache.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// EffectFactory
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
EffectFactory::EffectFactory(_In_ ID3D11Device* device)
|
||||
: pImpl(Impl::instancePool.DemandCreate(device))
|
||||
{
|
||||
}
|
||||
|
||||
EffectFactory::~EffectFactory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EffectFactory::EffectFactory(EffectFactory&& moveFrom)
|
||||
: pImpl(std::move(moveFrom.pImpl))
|
||||
{
|
||||
}
|
||||
|
||||
EffectFactory& EffectFactory::operator= (EffectFactory&& moveFrom)
|
||||
{
|
||||
pImpl = std::move(moveFrom.pImpl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
std::shared_ptr<IEffect> EffectFactory::CreateEffect(const EffectInfo& info, ID3D11DeviceContext* deviceContext)
|
||||
{
|
||||
return pImpl->CreateEffect(this, info, deviceContext);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
void EffectFactory::CreateTexture(const wchar_t* name, ID3D11DeviceContext* deviceContext, ID3D11ShaderResourceView** textureView)
|
||||
{
|
||||
return pImpl->CreateTexture(name, deviceContext, textureView);
|
||||
}
|
||||
|
||||
void EffectFactory::ReleaseCache()
|
||||
{
|
||||
pImpl->ReleaseCache();
|
||||
}
|
||||
|
||||
void EffectFactory::SetSharing(bool enabled)
|
||||
{
|
||||
pImpl->SetSharing(enabled);
|
||||
}
|
||||
|
||||
void EffectFactory::EnableNormalMapEffect(bool enabled)
|
||||
{
|
||||
pImpl->EnableNormalMapEffect( enabled );
|
||||
}
|
||||
|
||||
void EffectFactory::EnableForceSRGB(bool forceSRGB)
|
||||
{
|
||||
pImpl->EnableForceSRGB( forceSRGB );
|
||||
}
|
||||
|
||||
void EffectFactory::SetDirectory(_In_opt_z_ const wchar_t* path)
|
||||
{
|
||||
if (path && *path != 0)
|
||||
{
|
||||
wcscpy_s(pImpl->mPath, path);
|
||||
size_t len = wcsnlen(pImpl->mPath, MAX_PATH);
|
||||
if (len > 0 && len < (MAX_PATH - 1))
|
||||
{
|
||||
// Ensure it has a trailing slash
|
||||
if (pImpl->mPath[len - 1] != L'\\')
|
||||
{
|
||||
pImpl->mPath[len] = L'\\';
|
||||
pImpl->mPath[len + 1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
*pImpl->mPath = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user