2013-11-20 10:22:01 +01:00
|
|
|
#include "Core.h"
|
|
|
|
|
|
|
|
namespace Oyster
|
|
|
|
{
|
|
|
|
namespace Graphics
|
|
|
|
{
|
|
|
|
Core::Init::State Core::Init::CreateDeviceAndDeviceContext(bool SingleThreaded,bool Reference,bool ForceDX11)
|
|
|
|
{
|
|
|
|
UINT createDeviceFlags = 0;
|
|
|
|
|
|
|
|
if(Core::deviceContext)
|
|
|
|
{
|
|
|
|
Core::deviceContext->Release();
|
|
|
|
delete Core::deviceContext;
|
|
|
|
}
|
|
|
|
if(Core::device)
|
|
|
|
{
|
|
|
|
Core::device->Release();
|
|
|
|
delete Core::device;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if( SingleThreaded )
|
|
|
|
createDeviceFlags = ::D3D11_CREATE_DEVICE_SINGLETHREADED;
|
|
|
|
|
|
|
|
::D3D_DRIVER_TYPE driverType = ::D3D_DRIVER_TYPE_HARDWARE;
|
|
|
|
|
|
|
|
if(Reference)
|
|
|
|
driverType = D3D_DRIVER_TYPE_REFERENCE;
|
|
|
|
|
|
|
|
#if defined(DEBUG) || defined(_DEBUG)
|
|
|
|
log << "DirectX running in debug mode.\n";
|
|
|
|
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
|
|
|
#endif
|
2013-12-04 09:36:43 +01:00
|
|
|
|
|
|
|
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
2013-11-20 10:22:01 +01:00
|
|
|
|
|
|
|
D3D_FEATURE_LEVEL featureLevelsToTry[] =
|
|
|
|
{
|
|
|
|
D3D_FEATURE_LEVEL_11_0,
|
|
|
|
D3D_FEATURE_LEVEL_10_1,
|
|
|
|
D3D_FEATURE_LEVEL_10_0
|
|
|
|
};
|
|
|
|
D3D_FEATURE_LEVEL initiatedFeatureLevel;
|
|
|
|
|
|
|
|
if( FAILED( ::D3D11CreateDevice( NULL, // default adapter
|
|
|
|
driverType,
|
|
|
|
NULL, // no software device
|
|
|
|
createDeviceFlags,
|
|
|
|
featureLevelsToTry, 3, // default feature level array. DX11 support assumed
|
|
|
|
D3D11_SDK_VERSION,
|
|
|
|
&Core::device, // device
|
|
|
|
&initiatedFeatureLevel,
|
|
|
|
&Core::deviceContext ) ) ) // context
|
|
|
|
{ // if failed
|
|
|
|
if( Core::deviceContext ) { Core::deviceContext->Release(); Core::deviceContext = NULL; } // safe cleanup
|
|
|
|
if( Core::device ) { Core::device->Release(); Core::device = NULL; } // safe cleanup
|
|
|
|
}
|
|
|
|
|
|
|
|
if( driverType == ::D3D_DRIVER_TYPE_HARDWARE )
|
|
|
|
log << "D3D_DRIVER_TYPE_HARDWARE support discovered.\n";
|
|
|
|
else
|
|
|
|
log << "D3D_DRIVER_TYPE_REFERENCE support discovered.\n";
|
|
|
|
|
|
|
|
if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_11_0 )
|
|
|
|
{
|
|
|
|
log << "DirectX Featurelevel 11.0 supported.\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(ForceDX11)
|
|
|
|
return Init::Fail;
|
|
|
|
if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_10_1 )
|
|
|
|
{
|
|
|
|
log << "DirectX Featurelevel 10.1 supported.\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_10_0 )
|
|
|
|
{
|
|
|
|
log << "DirectX Featurelevel 10.0 supported.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(Core::device)
|
2013-12-18 20:28:06 +01:00
|
|
|
return Init::Success;
|
2013-11-20 10:22:01 +01:00
|
|
|
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::CreateSwapChain(HWND Window, int NrofBuffers,bool MSAA_Quality,bool Fullscreen, Oyster::Math::Float2 Size)
|
|
|
|
{
|
|
|
|
//generate static Swapchain Desc
|
|
|
|
DXGI_SWAP_CHAIN_DESC desc;
|
|
|
|
desc.OutputWindow=Window;
|
|
|
|
desc.BufferCount=NrofBuffers;
|
|
|
|
desc.Windowed=!Fullscreen;
|
|
|
|
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_UNORDERED_ACCESS;
|
|
|
|
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
|
|
|
desc.Flags=0;
|
|
|
|
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
|
|
|
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
|
|
|
|
desc.BufferDesc.RefreshRate.Denominator=1;
|
|
|
|
desc.BufferDesc.RefreshRate.Numerator=60;
|
|
|
|
|
2013-11-26 15:33:05 +01:00
|
|
|
desc.BufferDesc.Height = (UINT)Size.y;
|
|
|
|
desc.BufferDesc.Width = (UINT)Size.x;
|
2013-11-20 10:22:01 +01:00
|
|
|
|
|
|
|
if(Core::swapChain)
|
|
|
|
{
|
|
|
|
Core::swapChain->Release();
|
|
|
|
delete Core::swapChain;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Check and Set multiSampling
|
|
|
|
if(MSAA_Quality)
|
|
|
|
{
|
|
|
|
if(FAILED(Core::device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM,4,&desc.SampleDesc.Quality)))
|
|
|
|
{
|
|
|
|
log<< "Failed to check multisample quality levels (MSAAQuality).\n";
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
desc.SampleDesc.Count=4;
|
|
|
|
--desc.SampleDesc.Quality;
|
|
|
|
log << "Supported multisample quality levels (MSAAQuality): " << desc.SampleDesc.Quality+1 << "x\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
desc.SampleDesc.Count=1;
|
|
|
|
desc.SampleDesc.Quality=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Get Device Factory
|
|
|
|
::IDXGIDevice *dxgiDevice = NULL;
|
|
|
|
if( FAILED( Core::device->QueryInterface( __uuidof( IDXGIDevice ), (void**)&dxgiDevice ) ) )
|
|
|
|
{
|
|
|
|
log << "Failed to Query for the GPU's dxgiDevice.\nFailed to create swapChain for the GPU.\n";
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
::IDXGIAdapter *dxgiAdapter = NULL;
|
|
|
|
if( FAILED( dxgiDevice->GetParent( __uuidof( IDXGIAdapter ), (void**)&dxgiAdapter ) ) )
|
|
|
|
{
|
|
|
|
dxgiDevice->Release();
|
|
|
|
log << "Failed to get GPU's parent dxgiAdapter.\nFailed to create swapChain for the GPU.\n";
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
dxgiDevice->Release();
|
|
|
|
|
|
|
|
::IDXGIFactory *dxgiFactory = NULL;
|
|
|
|
if( FAILED( dxgiAdapter->GetParent( __uuidof( IDXGIFactory ), (void**)&dxgiFactory ) ) )
|
|
|
|
{
|
|
|
|
dxgiAdapter->Release();
|
|
|
|
log << "Failed to get GPU's parent dxgiFactory.\nFailed to create swapChain for the GPU.\n";
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
dxgiAdapter->Release();
|
|
|
|
|
|
|
|
//Create SwapChain
|
|
|
|
if( FAILED( dxgiFactory->CreateSwapChain( Core::device, &desc, &Core::swapChain ) ) )
|
|
|
|
{
|
|
|
|
dxgiFactory->Release();
|
|
|
|
log << "Failed to create swapChain for the GPU.\n";
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
dxgiFactory->Release();
|
|
|
|
|
2013-12-18 20:28:06 +01:00
|
|
|
return Init::Success;
|
2013-11-20 10:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::CreateDepthStencil(bool MSAA_Quality, Oyster::Math::Float2 Size)
|
|
|
|
{
|
|
|
|
D3D11_TEXTURE2D_DESC desc;
|
|
|
|
desc.MipLevels=1;
|
|
|
|
desc.ArraySize=1;
|
2013-12-18 20:28:06 +01:00
|
|
|
desc.Format = DXGI_FORMAT_R32_TYPELESS;
|
2013-11-20 10:22:01 +01:00
|
|
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
2013-12-18 20:28:06 +01:00
|
|
|
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
|
2013-11-20 10:22:01 +01:00
|
|
|
desc.CPUAccessFlags=0;
|
|
|
|
desc.MiscFlags=0;
|
2013-11-26 15:33:05 +01:00
|
|
|
desc.Height = (UINT)Size.y;
|
|
|
|
desc.Width = (UINT)Size.x;
|
2013-11-20 10:22:01 +01:00
|
|
|
|
|
|
|
if(Core::depthStencil)
|
|
|
|
{
|
|
|
|
Core::depthStencil->Release();
|
|
|
|
delete Core::depthStencil;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check and Set multiSampling
|
|
|
|
if(MSAA_Quality)
|
|
|
|
{
|
|
|
|
if(FAILED(Core::device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM,4,&desc.SampleDesc.Quality)))
|
|
|
|
{
|
|
|
|
log<< "Failed to check multisample quality levels (MSAAQuality).\n";
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
desc.SampleDesc.Count=4;
|
|
|
|
--desc.SampleDesc.Quality;
|
|
|
|
log << "Supported multisample quality levels (MSAAQuality): " << desc.SampleDesc.Quality+1 << "x\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
desc.SampleDesc.Count=1;
|
|
|
|
desc.SampleDesc.Quality=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ID3D11Texture2D* depthstencil;
|
|
|
|
|
|
|
|
if(FAILED(Core::device->CreateTexture2D(&desc,0,&depthstencil)))
|
2013-12-18 20:28:06 +01:00
|
|
|
{
|
2013-11-20 10:22:01 +01:00
|
|
|
return Init::Fail;
|
2013-12-18 20:28:06 +01:00
|
|
|
}
|
|
|
|
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
|
|
|
|
dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
|
|
|
|
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
|
|
|
dsvDesc.Flags = 0;
|
|
|
|
dsvDesc.Texture2D.MipSlice = 0;
|
|
|
|
if(Core::device->CreateDepthStencilView(depthstencil,&dsvDesc,&Core::depthStencil) != S_OK)
|
2013-11-20 10:22:01 +01:00
|
|
|
{
|
|
|
|
depthstencil->Release();
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
2013-12-18 20:28:06 +01:00
|
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
|
|
|
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
|
|
|
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
|
|
srvDesc.Texture2D.MipLevels = 1;
|
|
|
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
|
|
|
if(FAILED(Core::device->CreateShaderResourceView(depthstencil,&srvDesc,&Core::depthStencilUAV)))
|
|
|
|
{
|
|
|
|
depthStencil->Release();
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
2013-11-20 10:22:01 +01:00
|
|
|
depthstencil->Release();
|
|
|
|
|
2013-12-18 20:28:06 +01:00
|
|
|
return Init::Success;
|
2013-11-20 10:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::CreateBackBufferViews()
|
|
|
|
{
|
|
|
|
D3D11_UNORDERED_ACCESS_VIEW_DESC descView;
|
|
|
|
ZeroMemory( &descView, sizeof(descView) );
|
|
|
|
descView.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
|
|
|
|
descView.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
descView.Texture2D.MipSlice=0;
|
|
|
|
|
|
|
|
ID3D11Texture2D* backBuffer;
|
|
|
|
if(FAILED(Core::swapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),reinterpret_cast<void**>(&backBuffer))))
|
|
|
|
{
|
|
|
|
log << "Failed to get BackBuffer from Swapchain";
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
if(Core::backBufferRTV)
|
|
|
|
{
|
|
|
|
Core::backBufferRTV->Release();
|
|
|
|
delete Core::backBufferRTV;
|
|
|
|
}
|
|
|
|
if(FAILED(Core::device->CreateRenderTargetView(backBuffer,0,&Core::backBufferRTV)))
|
|
|
|
{
|
|
|
|
log << "Failed to create RTV for BackBuffer";
|
|
|
|
backBuffer->Release();
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
if(Core::backBufferUAV)
|
|
|
|
{
|
|
|
|
Core::backBufferUAV->Release();
|
|
|
|
delete Core::backBufferUAV;
|
|
|
|
}
|
|
|
|
if(FAILED(Core::device->CreateUnorderedAccessView(backBuffer,0,&Core::backBufferUAV)))
|
|
|
|
{
|
|
|
|
log << "Failed to create UAV for BackBuffer";
|
|
|
|
backBuffer->Release();
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
backBuffer->Release();
|
|
|
|
|
2013-12-18 20:28:06 +01:00
|
|
|
return Init::Success;
|
2013-11-20 10:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::CreateViewPort(Oyster::Math::Float2 Origin, Oyster::Math::Float2 Size)
|
|
|
|
{
|
|
|
|
if(Core::viewPort)
|
|
|
|
delete Core::viewPort;
|
|
|
|
Core::viewPort = new D3D11_VIEWPORT;
|
|
|
|
|
|
|
|
Core::viewPort->TopLeftX = Origin.x;
|
|
|
|
Core::viewPort->TopLeftY = Origin.y;
|
|
|
|
Core::viewPort->Width = Size.x;
|
|
|
|
Core::viewPort->Height = Size.y;
|
|
|
|
Core::viewPort->MinDepth = 0.0f;
|
|
|
|
Core::viewPort->MaxDepth = 1.0f;
|
|
|
|
|
2013-12-18 20:28:06 +01:00
|
|
|
return Init::Success;
|
2013-11-20 10:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::FullInit(HWND Window, bool MSAA_Quality, bool Fullscreen)
|
|
|
|
{
|
|
|
|
if(Init::CreateDeviceAndDeviceContext() == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Init::CreateSwapChain(Window, 1, MSAA_Quality, Fullscreen, Core::resolution) == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Init::CreateDepthStencil(MSAA_Quality, Core::resolution) == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Init::CreateBackBufferViews() == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Init::CreateViewPort(Oyster::Math::Float2::null, Core::resolution) == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
2013-12-18 20:28:06 +01:00
|
|
|
return Init::Success;
|
2013-11-20 10:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::ReInitialize(HWND Window, bool MSAA_Quality, bool Fullscreen)
|
|
|
|
{
|
|
|
|
if(Init::CreateSwapChain(Window, 1, MSAA_Quality, Fullscreen, Core::resolution) == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Init::CreateDepthStencil(MSAA_Quality, Core::resolution) == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Init::CreateBackBufferViews() == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Init::CreateViewPort(Oyster::Math::Float2::null, Core::resolution) == Init::Fail)
|
|
|
|
{
|
|
|
|
return Init::Fail;
|
|
|
|
}
|
|
|
|
|
2013-12-18 20:28:06 +01:00
|
|
|
return Init::Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::CreateLinkedShaderResourceFromTexture(ID3D11RenderTargetView** rtv, ID3D11ShaderResourceView** srv, ID3D11UnorderedAccessView** uav)
|
|
|
|
{
|
|
|
|
ID3D11Texture2D* tex;
|
|
|
|
D3D11_TEXTURE2D_DESC texDesc;
|
|
|
|
texDesc.Width = Core::resolution.x;
|
|
|
|
texDesc.Height = Core::resolution.y;
|
|
|
|
texDesc.MipLevels = 1;
|
|
|
|
texDesc.ArraySize = 1;
|
|
|
|
texDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
|
|
|
texDesc.SampleDesc.Count = 1;
|
|
|
|
texDesc.SampleDesc.Quality = 0;
|
|
|
|
texDesc.Usage = D3D11_USAGE_DEFAULT;
|
|
|
|
texDesc.CPUAccessFlags = 0;
|
|
|
|
texDesc.MiscFlags = 0;
|
|
|
|
texDesc.BindFlags = 0;
|
|
|
|
if(rtv)
|
|
|
|
{
|
|
|
|
texDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
|
|
|
|
}
|
|
|
|
if(srv)
|
|
|
|
{
|
|
|
|
texDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
|
|
|
|
}
|
|
|
|
if(uav)
|
|
|
|
{
|
|
|
|
texDesc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(FAILED(Core::device->CreateTexture2D(&texDesc,NULL,&tex)))
|
|
|
|
return State::Fail;
|
|
|
|
if(rtv)
|
|
|
|
{
|
|
|
|
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
|
|
|
|
rtvDesc.Format = texDesc.Format;
|
|
|
|
rtvDesc.Texture2D.MipSlice = 0;
|
|
|
|
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
|
|
|
|
|
|
|
Core::device->CreateRenderTargetView(tex, &rtvDesc, rtv);
|
|
|
|
}
|
|
|
|
if(srv)
|
|
|
|
{
|
|
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
|
|
|
srvDesc.Texture2D.MipLevels = 1;
|
|
|
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
|
|
|
srvDesc.Format = texDesc.Format;
|
|
|
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
|
|
|
|
|
|
Core::device->CreateShaderResourceView(tex,&srvDesc,srv);
|
|
|
|
}
|
|
|
|
if(uav)
|
|
|
|
{
|
|
|
|
D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
|
|
|
|
uavDesc.Texture2D.MipSlice = 0;
|
|
|
|
uavDesc.Format = texDesc.Format;
|
|
|
|
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
|
|
|
|
|
|
|
|
Core::device->CreateUnorderedAccessView(tex,&uavDesc,uav);
|
|
|
|
}
|
|
|
|
|
|
|
|
SAFE_RELEASE(tex);
|
|
|
|
|
|
|
|
|
|
|
|
return State::Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
Core::Init::State Core::Init::CreateLinkedShaderResourceFromStructuredBuffer(Buffer** Structured, ID3D11ShaderResourceView** srv, ID3D11UnorderedAccessView** uav)
|
|
|
|
{
|
|
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
|
|
|
|
desc.Buffer.FirstElement=0;
|
|
|
|
desc.Buffer.ElementWidth = (*Structured)->GetElementCount();
|
|
|
|
desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
|
|
desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
|
|
|
|
|
|
|
|
if(Core::device->CreateShaderResourceView(**(Structured),&desc, srv)==S_OK)
|
|
|
|
{
|
|
|
|
return State::Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
return State::Fail;
|
2013-11-20 10:22:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|