#include "stdafx.h"
#include "D3DApplication.h"
#include <DXGI1_2.h>
#include <DirectXTex.h>


D3DApplication::D3DApplication()
	: Application(),
	m_hWnd( NULL ),
	m_pDXGISwapChain1( NULL ),
	m_pSwapChain( NULL ),
	m_pd3dDevice( NULL ),
	m_pd3dDevice1( NULL ),
	m_pd3dDeviceCtx( NULL ),
	m_pd3dDeviceCtx1( NULL ),
	m_pd3dBackBuffer( NULL ),
	m_pd3dVBuffer( NULL ),
	m_pd3dIBuffer( NULL ),
	m_pd3dSamplerState( NULL ),
	m_pd3dBlendState( NULL ),
	m_pVS( NULL ),
	m_pPS( NULL ),
	m_pd3dLayout( NULL ),
	m_d3dFeatureLevel( D3D_FEATURE_LEVEL_11_1 ),
	m_driverType( D3D_DRIVER_TYPE_UNKNOWN ),
	m_pImage( NULL ),
	m_pWarping( NULL )
{
}

D3DApplication::~D3DApplication()
{
	ClearD3D();
}

void D3DApplication::Shutdown()
{
	Application::Shutdown();
}

int D3DApplication::Run()
{
	MSG msg = { 0 };

	while( TRUE )
	{
		// Check to see if any messages are waiting in the queue
		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
		{	
			// translate keystroke messages into the right format
			TranslateMessage( &msg );

			// send the message to the WindowProc function
			DispatchMessage( &msg );

			// check to see if it's time to quit
			if( msg.message == WM_QUIT )
			{
				break;
			}
		}
		else
		{
			InitFrame();
			Render();
			Swap();
			ExitFrame();
		}
	}

	return (int)msg.wParam;
}

void D3DApplication::InitFrame()
{
}

void D3DApplication::Render()
{
	static float bgColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	m_pd3dDeviceCtx->ClearRenderTargetView( m_pd3dBackBuffer, bgColor );

	float bf [4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	m_pd3dDeviceCtx->OMSetBlendState( m_pd3dBlendState, bf, 0xffffffff );

	m_pd3dDeviceCtx->OMSetRenderTargets( 1, &m_pd3dBackBuffer, NULL );

	m_pd3dDeviceCtx->VSSetShader( m_pVS, NULL, 0 );
	m_pd3dDeviceCtx->PSSetShader( m_pPS, NULL, 0 );
	m_pd3dDeviceCtx->PSSetShaderResources( 0, 1, &m_pImage );
	m_pd3dDeviceCtx->PSSetSamplers( 0, 1, &m_pd3dSamplerState );

	m_pd3dDeviceCtx->PSSetShaderResources( 1, 1, &m_pWarping );
	m_pd3dDeviceCtx->DrawIndexed( 6, 0, 0 );
}

void D3DApplication::Swap()
{
	m_pSwapChain->Present( 1, 0 );
}

void D3DApplication::ExitFrame()
{
}

BOOL D3DApplication::SetupInstance( int argc, LPWSTR *argv )
{
	if( !Application::SetupInstance( argc, argv ) )
	{
		return FALSE;
	}

	if( argc != 2 )
	{
		return FALSE;
	}

	WNDCLASSEX wc;
	ZeroMemory( &wc, sizeof( WNDCLASSEX ) );
	wc.cbSize = sizeof( WNDCLASSEX );
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc = D3DApplication::WndProc;
	wc.hInstance = m_hInstance;
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	//wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
	wc.lpszClassName = D3DWINDOWCLASS;
	if( !RegisterWindowClass( &wc ) )
	{
		Log( "RegisterClass failed\n" );
		return FALSE;
	}

	RECT rc = { 0, 0, 800, 600 }; 
	AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); 
	m_hWnd = CreateWindow(
		D3DWINDOWCLASS,
		L"d3d wb sample", 
		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 
		CW_USEDEFAULT, CW_USEDEFAULT, 
		rc.right - rc.left, 
		rc.bottom - rc.top, 
		nullptr, 
		nullptr, 
		m_hInstance, 
		(LPVOID)this ); 
	if( !m_hWnd ) 
	{
		return E_FAIL; 
	}
 
	ShowWindow( m_hWnd, SW_SHOW ); 

	if( InitD3D() )
	{
		HRESULT hr;
		hr = CreateTextureFromWICFile( argv[0], &m_pImage );
		if( FAILED( hr ) )
		{
			printf( "Loading \"%s\" failed with 0x08X\n", argv[0], hr );
			return false;
		}
		hr = CreateTextureFromDDSFile( argv[1], &m_pWarping );
		if( FAILED( hr ) )
		{
			printf( "Loading \"%s\" failed with 0x08X\n", argv[1], hr );
			return false;
		}
	}

	return TRUE;
}

BOOL D3DApplication::InitD3D()
{
	HRESULT hr = S_OK; 
 
	RECT rc; 
	GetClientRect( m_hWnd, &rc ); 
	UINT width = rc.right - rc.left; 
	UINT height = rc.bottom - rc.top; 
 
	UINT createDeviceFlags = 0; 
#ifdef _DEBUG 
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 
#endif 
 
	D3D_DRIVER_TYPE driverTypes[] = 
	{ 
		D3D_DRIVER_TYPE_HARDWARE, 
		D3D_DRIVER_TYPE_WARP, 
		D3D_DRIVER_TYPE_REFERENCE, 
	}; 
	UINT numDriverTypes = ARRAYSIZE( driverTypes ); 

	D3D_FEATURE_LEVEL featureLevels[] = 
	{ 
		D3D_FEATURE_LEVEL_11_1, 
		D3D_FEATURE_LEVEL_11_0, 
		D3D_FEATURE_LEVEL_10_1, 
		D3D_FEATURE_LEVEL_10_0, 
	}; 
	UINT numFeatureLevels = ARRAYSIZE( featureLevels ); 
 
	for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ) 
	{ 
		m_driverType = driverTypes[driverTypeIndex]; 
		hr = D3D11CreateDevice( nullptr, m_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &m_pd3dDevice, &m_d3dFeatureLevel, &m_pd3dDeviceCtx );

		if ( hr == E_INVALIDARG ) 
		{ 
			// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it 
			hr = D3D11CreateDevice( nullptr, m_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, D3D11_SDK_VERSION, &m_pd3dDevice, &m_d3dFeatureLevel, &m_pd3dDeviceCtx ); 
		} 
 
		if( SUCCEEDED( hr ) ) 
		{
			break; 
		}
	} 
	
	if( FAILED( hr ) ) 
	{
		LogEx( "D3D11CreateDevice failed with 0x08X", hr );
		return FALSE; 
	}
 
	// Obtain DXGI factory from device (since we used nullptr for pAdapter above) 
	IDXGIFactory1* dxgiFactory = nullptr; 
	{ 
		IDXGIDevice* dxgiDevice = nullptr; 
		hr = m_pd3dDevice->QueryInterface( __uuidof( IDXGIDevice ), reinterpret_cast<void**>( &dxgiDevice ) ); 
		if( SUCCEEDED( hr ) ) 
		{ 
			IDXGIAdapter* adapter = nullptr; 
			hr = dxgiDevice->GetAdapter( &adapter ); 
			if( SUCCEEDED( hr ) ) 
			{ 
				hr = adapter->GetParent( __uuidof( IDXGIFactory1 ), reinterpret_cast<void**>( &dxgiFactory ) ); 
				adapter->Release(); 
			} 
			dxgiDevice->Release(); 
		} 
	} 
	if( FAILED( hr ) ) 
	{
		LogEx( "Getting IDXGIFactory1 failed with 0x08X", hr );
		return FALSE; 
	}
 
	// Create swap chain 
	IDXGIFactory2* dxgiFactory2 = nullptr; 
	hr = dxgiFactory->QueryInterface( __uuidof( IDXGIFactory2 ), reinterpret_cast<void**>( &dxgiFactory2 ) ); 
	if ( dxgiFactory2 ) 
	{ 
		// DirectX 11.1 or later 
		hr = m_pd3dDevice->QueryInterface( __uuidof( ID3D11Device1 ), reinterpret_cast<void**>( &m_pd3dDevice1 ) ); 
		if( SUCCEEDED( hr ) ) 
		{ 
			m_pd3dDeviceCtx->QueryInterface( __uuidof( ID3D11DeviceContext1 ), reinterpret_cast<void**>( &m_pd3dDeviceCtx1 ) ); 
		} 

		DXGI_SWAP_CHAIN_DESC1 sd; 
		ZeroMemory( &sd, sizeof( sd ) ); 
		sd.Width = width; 
		sd.Height = height; 
		sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
		sd.SampleDesc.Count = 1; 
		sd.SampleDesc.Quality = 0; 
		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 
		sd.BufferCount = 1; 

		hr = dxgiFactory2->CreateSwapChainForHwnd( m_pd3dDevice, m_hWnd, &sd, nullptr, nullptr, &m_pDXGISwapChain1 ); 
		if( SUCCEEDED( hr ) ) 
		{ 
			hr = m_pDXGISwapChain1->QueryInterface( __uuidof( IDXGISwapChain ), reinterpret_cast<void**>( &m_pSwapChain ) ); 
		} 
 
		dxgiFactory2->Release(); 
	} 
	else 
	{ 
		// DirectX 11.0 systems 
		DXGI_SWAP_CHAIN_DESC sd; 
		ZeroMemory( &sd, sizeof( sd ) ); 
		sd.BufferCount = 1; 
		sd.BufferDesc.Width = width; 
		sd.BufferDesc.Height = height; 
		sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
		sd.BufferDesc.RefreshRate.Numerator = 60; 
		sd.BufferDesc.RefreshRate.Denominator = 1; 
		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 
		sd.OutputWindow = m_hWnd; 
		sd.SampleDesc.Count = 1; 
		sd.SampleDesc.Quality = 0; 
		sd.Windowed = TRUE; 

		hr = dxgiFactory->CreateSwapChain( m_pd3dDevice, &sd, &m_pSwapChain ); 
	} 
 
	// Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut 
	dxgiFactory->MakeWindowAssociation( m_hWnd, DXGI_MWA_NO_ALT_ENTER ); 

	dxgiFactory->Release(); 

	if( FAILED( hr ) ) 
	{
		LogEx( "Swapchain creation failed with 0x08X", hr );
		return FALSE; 
	} 

	// Create a render target view 
	ID3D11Texture2D* pBackBuffer = nullptr; 
	hr = m_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( &pBackBuffer ) ); 
	if( FAILED( hr ) ) 
	{
		LogEx( "GetBuffer failed with 0x08X", hr );
		return FALSE; 
	}

	hr = m_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &m_pd3dBackBuffer ); 
	pBackBuffer->Release(); 
	if( FAILED( hr ) ) 
	{
		LogEx( "CreateRenderTargetView failed with 0x08X", hr );
		return FALSE; 
	}
 
	m_pd3dDeviceCtx->OMSetRenderTargets( 1, &m_pd3dBackBuffer, nullptr ); 
 
	// Setup the viewport 
	D3D11_VIEWPORT vp; 
	vp.Width = (FLOAT)width; 
	vp.Height = (FLOAT)height; 
	vp.MinDepth = 0.0f; 
	vp.MaxDepth = 1.0f; 
	vp.TopLeftX = 0; 
	vp.TopLeftY = 0; 
	m_pd3dDeviceCtx->RSSetViewports( 1, &vp ); 

	// Create the vertex shader
	hr = m_pd3dDevice->CreateVertexShader( g_VS, sizeof( g_VS ), NULL, &m_pVS );
	if( FAILED( hr ) )
	{
		LogEx( "CreateVertexShader failed with 0x08X", hr );
		return FALSE;
	}

    // Define the input layout
    D3D11_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * sizeof( FLOAT ), D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };
    UINT numElements = ARRAYSIZE( layout );

    // Create the input layout
	hr = m_pd3dDevice->CreateInputLayout( layout, numElements, g_VS, sizeof( g_VS ), &m_pd3dLayout );
	if( FAILED( hr ) )
	{
		LogEx( "CreateInputLayout failed with 0x08X", hr );
		return FALSE;
	}

    // Create the pixel shader for warping/blending
    m_pd3dDeviceCtx->IASetInputLayout( m_pd3dLayout );

	// Create the pixel shader
	hr = m_pd3dDevice->CreatePixelShader( g_PS, sizeof( g_PS ), NULL, &m_pPS );
	if( FAILED( hr ) )
	{
		LogEx( "CreatePixelShader failed with 0x08X", hr );
		return FALSE;
	}

	// Set primitive topology
	m_pd3dDeviceCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

	// Create the state objects
	D3D11_SAMPLER_DESC sampDesc;
	ZeroMemory( &sampDesc, sizeof( sampDesc ) );
	sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	sampDesc.MinLOD = 0;
	sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
	hr = m_pd3dDevice->CreateSamplerState( &sampDesc, &m_pd3dSamplerState );
	if( FAILED( hr ) )
	{
		LogEx( "CreateSamplerState failed with 0x08X", hr );
		return FALSE;
	}

	D3D11_BLEND_DESC dsc = 
	{
		false,
		false,
		{
			true,
			D3D11_BLEND_SRC_ALPHA,
			D3D11_BLEND_INV_SRC_ALPHA,
			D3D11_BLEND_OP_ADD,
			D3D11_BLEND_ZERO,
			D3D11_BLEND_ZERO,
			D3D11_BLEND_OP_ADD,
			D3D11_COLOR_WRITE_ENABLE_ALL
		} 
	};
	hr = m_pd3dDevice->CreateBlendState( &dsc, &m_pd3dBlendState );
    if( FAILED(hr) )
	{
		LogEx( "CreateBlendState failed with 0x08X", hr );
		return NULL;
	}
 
	// vertices
	std::vector<SimpleVertex> vertices;
	vertices.push_back( SimpleVertex( -1.,  1., 0., 1., 0., 0. ) );
	vertices.push_back( SimpleVertex(  1.,  1., 0., 1., 1., 0. ) );
	vertices.push_back( SimpleVertex(  1., -1., 0., 1., 1., 1. ) );
	vertices.push_back( SimpleVertex( -1., -1., 0., 1., 0., 1. ) );

	// indices
	std::vector<WORD> indices;
	indices.push_back( 0 );
	indices.push_back( 1 );
	indices.push_back( 2 );
	indices.push_back( 2 );
	indices.push_back( 3 );
	indices.push_back( 0 );

	// Create vertex buffer
	UINT nverts;
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory( &InitData, sizeof( InitData ) );
	nverts = vertices.size();
	InitData.pSysMem = &vertices[0];

	D3D11_BUFFER_DESC bd;
	ZeroMemory( &bd, sizeof( bd ) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( SimpleVertex ) * nverts;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	hr = m_pd3dDevice->CreateBuffer( &bd, &InitData, &m_pd3dVBuffer );

	// Set vertex buffer
	UINT stride = sizeof( SimpleVertex );
	UINT offset = 0;
	m_pd3dDeviceCtx->IASetVertexBuffers( 0, 1, &m_pd3dVBuffer, &stride, &offset );

	// Create index buffer
	InitData.pSysMem = &indices[0];

	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = indices.size() * sizeof( WORD );
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	hr = m_pd3dDevice->CreateBuffer( &bd, &InitData, &m_pd3dIBuffer );

	// Set index buffer
	m_pd3dDeviceCtx->IASetIndexBuffer( m_pd3dIBuffer, DXGI_FORMAT_R16_UINT, 0 );

	return TRUE; 
}

void D3DApplication::ClearD3D()
{
	// free all D3D stuff here
}

LRESULT CALLBACK D3DApplication::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	if( msg == WM_CREATE )
	{
		D3DApplication *app = NULL;
		CREATESTRUCT *cs = NULL;
		cs = (CREATESTRUCT*)lParam;
		app = (D3DApplication*)cs->lpCreateParams;

		if( !app )
		{
			return -1;
		}
		SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)app );
		return 0;
	}
	else
	{
		D3DApplication *app = NULL;
		app = (D3DApplication*)GetWindowLongPtr( hWnd, GWLP_USERDATA );
		if( app )
		{
			return app->D3DApplicationWndProc( hWnd, msg, wParam, lParam );
		}
	}
	return DefWindowProc( hWnd, msg, wParam, lParam );
}

LRESULT D3DApplication::D3DApplicationWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	switch( msg )
	{
	case WM_SIZE:
		//{
		//	Resize( LOWORD( lParam ), HIWORD( lParam ) );
		//}
		return 0;
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hdc;
			hdc = BeginPaint( hWnd, &ps );
			
			bool needPaint = false;
			if( needPaint )
			{
				RECT rc;
				GetClientRect( hWnd, &rc );
				FillRect( hdc, &rc, (HBRUSH)(COLOR_WINDOW + 1) );
			}
			EndPaint( hWnd, &ps );
		}
		break;
	case WM_KEYDOWN:
		switch( wParam )
		{
		case VK_ESCAPE:
			PostQuitMessage( 0 );
			break;
		}
	case WM_DESTROY:
		PostQuitMessage( 0 );
		break;
	default:
		return DefWindowProc( hWnd, msg, wParam, lParam );
	}
	return 0;
}

HRESULT D3DApplication::CreateTextureFromDDSFile( LPCWSTR file, ID3D11ShaderResourceView **srv )
{
	DirectX::TexMetadata mdata;
	HRESULT hr = DirectX::GetMetadataFromDDSFile( file, DirectX::DDS_FLAGS_NONE, mdata );
	if( FAILED(hr) )
	{
        return hr;
	}

	if( mdata.dimension == DirectX::TEX_DIMENSION_TEXTURE3D )
    {
		if( mdata.arraySize > 1 )
        {
			return E_NOTIMPL;
        }
    }

	switch( mdata.format )
	{
	case DXGI_FORMAT_BC6H_TYPELESS:
	case DXGI_FORMAT_BC6H_UF16:
	case DXGI_FORMAT_BC6H_SF16:
	case DXGI_FORMAT_BC7_TYPELESS:
	case DXGI_FORMAT_BC7_UNORM:
	case DXGI_FORMAT_BC7_UNORM_SRGB:
		if ( m_d3dFeatureLevel < D3D_FEATURE_LEVEL_11_0 )
		{
            // BC6H/BC7 requires DirectX 11 hardware
			return E_NOTIMPL;
        }
        break;
	default:
		{
			UINT flags = 0;
			hr = m_pd3dDevice->CheckFormatSupport( mdata.format, &flags );
			if( FAILED( hr ) || !( flags & ( D3D11_FORMAT_SUPPORT_TEXTURE1D | D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURE3D ) ) )
			{
				// Format not supported by DirectX hardware
				return E_NOTIMPL;
			}
		}
		break;
    }

	DirectX::ScratchImage image;
	hr = DirectX::LoadFromDDSFile( file, DirectX::DDS_FLAGS_NONE, &mdata, image );
	if( FAILED(hr) )
	{
        // Failed to load texture file
        return hr;
    }

	// Special case to make sure Texture cubes remain arrays
	mdata.miscFlags &= ~DirectX::TEX_MISC_TEXTURECUBE;

    return CreateShaderResourceView( m_pd3dDevice, image.GetImages(), image.GetImageCount(), mdata, srv );
}

HRESULT D3DApplication::CreateTextureFromWICFile( LPCWSTR file, ID3D11ShaderResourceView **srv )
{
	CoInitialize( NULL );

	DirectX::TexMetadata mdata;
	HRESULT hr = DirectX::GetMetadataFromWICFile( file, DirectX::DDS_FLAGS_NONE, mdata );
	if( FAILED(hr) )
	{
        return hr;
	}

	if( mdata.dimension == DirectX::TEX_DIMENSION_TEXTURE3D )
    {
		if( mdata.arraySize > 1 )
        {
			return E_NOTIMPL;
        }
    }

	switch( mdata.format )
	{
	case DXGI_FORMAT_BC6H_TYPELESS:
	case DXGI_FORMAT_BC6H_UF16:
	case DXGI_FORMAT_BC6H_SF16:
	case DXGI_FORMAT_BC7_TYPELESS:
	case DXGI_FORMAT_BC7_UNORM:
	case DXGI_FORMAT_BC7_UNORM_SRGB:
		if ( m_d3dFeatureLevel < D3D_FEATURE_LEVEL_11_0 )
		{
            // BC6H/BC7 requires DirectX 11 hardware
			return E_NOTIMPL;
        }
        break;
	default:
		{
			UINT flags = 0;
			hr = m_pd3dDevice->CheckFormatSupport( mdata.format, &flags );
			if( FAILED( hr ) || !( flags & ( D3D11_FORMAT_SUPPORT_TEXTURE1D | D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURE3D ) ) )
			{
				// Format not supported by DirectX hardware
				return E_NOTIMPL;
			}
		}
		break;
    }

	DirectX::ScratchImage image;
	hr = DirectX::LoadFromWICFile( file, DirectX::DDS_FLAGS_NONE, &mdata, image );
	if( FAILED(hr) )
	{
        // Failed to load texture file
        return hr;
    }

	// Special case to make sure Texture cubes remain arrays
	mdata.miscFlags &= ~DirectX::TEX_MISC_TEXTURECUBE;

    hr = CreateShaderResourceView( m_pd3dDevice, image.GetImages(), image.GetImageCount(), mdata, srv );
	
	CoUninitialize();
	
	return hr;
}
