Bye-Bye

Published September 01, 2006
Advertisement
For any 24 fans out there, I'm "going dark" for a bit. NO, I don't mean I'm going for some crazy body-painting thing. Just mean I'm going offline and disappearing into the "real world" for a while...

Whilst I'm sure the DX forum will look after itself Kazgoroth has offered to keep an eye out for any bad behaviour...

Given that I probably won't be here to update my journal I'll leave you with some code:

D3DX9MeshToD3DX10Mesh.h
#ifndef INC_D3X9MESHTOD3DX10MESH_H#define INC_D3DX9MESHTOD3DX10MESH_H#include #include #include namespace MeshConv{	HRESULT CreateD3DX10MeshFromD3DX9Mesh( ID3DXMesh* pInMesh, ID3DX10Mesh** pOutMesh, ID3D10Device *pDevice );};#endif


D3DX9MeshToD3DX10Mesh.cpp
// Make sure the PCH goes first//-----------------------------#include "DXUT.h"// Include the OS headers//-----------------------#include #include #pragma warning( disable: 4996 )#include #pragma warning( default: 4996 )// Include the D3D10 headers//--------------------------#include #include #include // Include any project-specific headers//-------------------------------------#include "Globals.h"#include "D3DX9MeshToD3DX10Mesh.h"namespace MeshConv{	HRESULT			ConvertDeclaration( const D3DVERTEXELEMENT9 original[ MAX_FVF_DECL_SIZE ], D3D10_INPUT_ELEMENT_DESC output[ MAX_FVF_DECL_SIZE ] );	LPCSTR			ConvertSemantic( const D3DDECLUSAGE& d3d9Form );	DXGI_FORMAT		ConvertType( const D3DDECLTYPE& d3d9Form );	HRESULT			CopyIndexBufferData( ID3DXMesh* pMesh9, ID3DX10Mesh* pMesh10 );	HRESULT			CopyVertexBufferData( ID3DXMesh* pMesh9, ID3DX10Mesh* pMesh10 );	HRESULT			ConfigureAttributeTable( ID3DXMesh* pMesh9, ID3DX10Mesh* pMesh10 );	HRESULT CreateD3DX10MeshFromD3DX9Mesh( ID3DXMesh* pInMesh, ID3DX10Mesh** pOutMesh, ID3D10Device *pDevice )	{		// Check the parameters		if( (NULL == pInMesh) || (NULL == pDevice) )		{			ERR_OUT( L"One or more parameters are NULL when they shouldn't be!" );			return E_INVALIDARG;		}		// Retrieve the declaration for the incoming data		D3DVERTEXELEMENT9 OriginalDeclaration[ MAX_FVF_DECL_SIZE ];		if( FAILED( pInMesh->GetDeclaration( OriginalDeclaration ) ) )		{			ERR_OUT( L"Could not retrieve declaration from the D3DX9 mesh" );			return E_FAIL;		}		// Convert the vertex declaration		D3D10_INPUT_ELEMENT_DESC NewDeclaration[ MAX_FVF_DECL_SIZE ];		ZeroMemory( NewDeclaration, sizeof( NewDeclaration ) );		if( FAILED( ConvertDeclaration( OriginalDeclaration, NewDeclaration ) ) )		{			ERR_OUT( L"Could not convert incoming D3D9 declaration to a D3D10 declaration" );			return E_FAIL;		}		// Determine the number of elements in the declaration		UINT DeclSize = D3DXGetDeclLength( OriginalDeclaration );		// Convert the mesh options		UINT NewOptions = 0;		if( 0 != (pInMesh->GetOptions() & D3DXMESH_32BIT) )			NewOptions = D3DX10_MESH_32_BIT;		// Create the D3D10 Mesh		if( FAILED( D3DX10CreateMesh( pDevice, NewDeclaration, DeclSize, "POSITION", pInMesh->GetNumVertices(), pInMesh->GetNumFaces(), NewOptions, pOutMesh ) ) )		{			ERR_OUT( L"Could not create ID3DX10Mesh object!" );			return E_FAIL;		}		else		{			INFO_OUT( L"Successfully created/allocated a D3DX10 mesh based on the D3DX9 input." );			WCHAR wcMeshInfo[512];			StringCchPrintf( wcMeshInfo, 512,	L"(INFO) : D3DX10 mesh has %d vertices and %d faces\n",												(*pOutMesh)->GetVertexCount(),												(*pOutMesh)->GetFaceCount()											);						OutputDebugString( wcMeshInfo );		}		// Now we fill the D3D10 mesh with data		if( FAILED( CopyIndexBufferData( pInMesh, *pOutMesh ) ) )		{			ERR_OUT( L"Unable to copy the raw index data from D3X9 mesh to D3DX10 mesh." );			return E_FAIL;		}		if( FAILED( CopyVertexBufferData( pInMesh, *pOutMesh ) ) )		{			ERR_OUT( L"Unable to copy the raw vertex data from D3DX9 mesh to D3DX10 mesh." );			return E_FAIL;		}		INFO_OUT( L"Successfully copied all raw vertex and index data from D3DX9 mesh to D3DX10 mesh." );		// Set up the attribute table		if( FAILED( ConfigureAttributeTable( pInMesh, *pOutMesh ) ) )		{			ERR_OUT( L"Unable to configure attribute table for new mesh" );			return E_FAIL;		}		// Process the mesh accordingly		if( FAILED( (*pOutMesh)->GenerateAdjacencyAndPointReps( 0.0f ) ) )		{			ERR_OUT( L"Failed to generate adjacency for D3DX10 mesh" );			return E_FAIL;		}		if( FAILED( (*pOutMesh)->Optimize( D3DX10_MESHOPT_COMPACT | D3DX10_MESHOPT_ATTR_SORT | D3DX10_MESHOPT_VERTEX_CACHE, NULL, NULL ) ) )		{			ERR_OUT( L"Failed to optimize mesh (compact, attribute sort and vertex cache)" );			return E_FAIL;		}		INFO_OUT( L"Successfully created a D3DX10 mesh from a D3DX9 mesh." );		return S_OK;	}	HRESULT ConvertDeclaration( const D3DVERTEXELEMENT9 original[ MAX_FVF_DECL_SIZE ], D3D10_INPUT_ELEMENT_DESC output[ MAX_FVF_DECL_SIZE ] )	{		for( UINT i = 0; i < D3DXGetDeclLength( original ); ++i )		{			// Convert this element			output.SemanticName			= ConvertSemantic( static_cast< D3DDECLUSAGE >( original.Usage ) );			output.SemanticIndex			= original.UsageIndex;			output.AlignedByteOffset		= original.Offset;			output.InputSlot				= original.Stream;			output.InputSlotClass		= D3D10_INPUT_PER_VERTEX_DATA;			output.InstanceDataStepRate	= 0;			output.Format				= ConvertType( static_cast< D3DDECLTYPE >( original.Type ) );		}		return S_OK;	}	LPCSTR ConvertSemantic( const D3DDECLUSAGE& d3d9Form )	{		switch( d3d9Form )		{			case D3DDECLUSAGE_POSITION:				return "POSITION";			case D3DDECLUSAGE_BLENDWEIGHT:			return "BLENDWEIGHT";			case D3DDECLUSAGE_BLENDINDICES:			return "BLENDINDICES";			case D3DDECLUSAGE_NORMAL:				return "NORMAL";			case D3DDECLUSAGE_PSIZE:				return "PSIZE";			case D3DDECLUSAGE_TEXCOORD:				return "TEXCOORD";			case D3DDECLUSAGE_TANGENT:				return "TANGENT";			case D3DDECLUSAGE_BINORMAL:				return "BINORMAL";			case D3DDECLUSAGE_TESSFACTOR:			return "TESSFACTOR";			case D3DDECLUSAGE_POSITIONT:			return "POSITIONT";			case D3DDECLUSAGE_COLOR:				return "COLOR";			case D3DDECLUSAGE_FOG:					return "FOG";			case D3DDECLUSAGE_DEPTH:				return "DEPTH";			case D3DDECLUSAGE_SAMPLE:				return "SAMPLE";			default:								return "UNKNOWN";		}	}	DXGI_FORMAT	ConvertType( const D3DDECLTYPE& d3d9Form )	{		switch( d3d9Form )		{			case D3DDECLTYPE_FLOAT1:				return DXGI_FORMAT_R32_FLOAT;			case D3DDECLTYPE_FLOAT2:				return DXGI_FORMAT_R32G32_FLOAT;			case D3DDECLTYPE_FLOAT3:				return DXGI_FORMAT_R32G32B32_FLOAT;			case D3DDECLTYPE_FLOAT4:				return DXGI_FORMAT_R32G32B32A32_FLOAT;			case D3DDECLTYPE_D3DCOLOR:				return DXGI_FORMAT_R8G8B8A8_UNORM;			case D3DDECLTYPE_UBYTE4:				return DXGI_FORMAT_R8G8B8A8_UINT;			case D3DDECLTYPE_SHORT2:				return DXGI_FORMAT_R16G16_SINT;			case D3DDECLTYPE_SHORT4:				return DXGI_FORMAT_R16G16B16A16_SINT;			case D3DDECLTYPE_UBYTE4N:				return DXGI_FORMAT_R8G8B8A8_UNORM;			case D3DDECLTYPE_SHORT2N:				return DXGI_FORMAT_R16G16_SNORM;			case D3DDECLTYPE_SHORT4N:				return DXGI_FORMAT_R16G16B16A16_SNORM;			case D3DDECLTYPE_USHORT2N:				return DXGI_FORMAT_R16G16_UNORM;			case D3DDECLTYPE_USHORT4N:				return DXGI_FORMAT_R16G16B16A16_UNORM;			case D3DDECLTYPE_UDEC3:					return DXGI_FORMAT_R10G10B10A2_UINT;			case D3DDECLTYPE_DEC3N:					return DXGI_FORMAT_R10G10B10A2_UNORM;			case D3DDECLTYPE_FLOAT16_2:				return DXGI_FORMAT_R16G16_FLOAT;			case D3DDECLTYPE_FLOAT16_4:				return DXGI_FORMAT_R16G16B16A16_FLOAT;			case D3DDECLTYPE_UNUSED:			default:								return DXGI_FORMAT_UNKNOWN;		}	}	HRESULT CopyIndexBufferData( ID3DXMesh* pMesh9, ID3DX10Mesh* pMesh10 )	{		// verify inputs		if( (NULL == pMesh9) || (NULL == pMesh10) )		{			ERR_OUT( L"Both input mesh's must be non-NULL." );			return E_INVALIDARG;		}		CComPtr< ID3DX10MeshBuffer > pIBuffer10;		if( FAILED( pMesh10->GetIndexBuffer( &pIBuffer10 ) ) )		{			ERR_OUT( L"Unable to retrieve D3DX10 mesh's index buffer." );			return E_FAIL;		}		// switch depending on 16 or 32 bit indices..		if( 0 != (pMesh10->GetFlags() & D3DX10_MESH_32_BIT) )		{			INFO_OUT( L"Indices are in 32bit form, performing appropriate copy..." );			if( pIBuffer10->GetSize() != (pMesh10->GetFaceCount() * 3 * sizeof( unsigned __int32 ) ) )			{				ERR_OUT( L"The number of bytes in the index buffer does NOT match the expected size!" );				return E_FAIL;			}			SIZE_T stRawIndices10 = 0;			unsigned __int32 *pRawIndices10 = NULL;			if( SUCCEEDED( pIBuffer10->Map( reinterpret_cast< void** >( &pRawIndices10 ), &stRawIndices10 ) ) )			{				// We now have direct access to the index buffer data				// so we need to lock the incoming, D3DX9, buffer and copy the contents				// across...				unsigned __int32 *pRawIndices9 = NULL;				if( SUCCEEDED( pMesh9->LockIndexBuffer( 0, reinterpret_cast< LPVOID* >( &pRawIndices9 ) ) ) )				{					memcpy_s(	pRawIndices10, 								stRawIndices10, 								pRawIndices9, 								pMesh9->GetNumFaces() * 3 * sizeof( unsigned __int32 ) 							);					// Tidy up					pMesh9->UnlockIndexBuffer( );				}				else				{					ERR_OUT( L"Unable to lock the D3DX9 mesh's index buffer!" );					pIBuffer10->Unmap( );					return E_FAIL;				}				// Tidy up..				pIBuffer10->Unmap( );			}			else			{				ERR_OUT( L"Unable to Map() D3DX10's index buffer!" );				return E_FAIL;			}		}		else		{			INFO_OUT( L"Indices are in 16bit form, performing appropriate copy..." );			if( pIBuffer10->GetSize() != (pMesh10->GetFaceCount() * 3 * sizeof( unsigned __int16 ) ) )			{				ERR_OUT( L"The number of bytes in the index buffer does NOT match the expected size!" );				return E_FAIL;			}			SIZE_T stRawIndices10 = 0;			unsigned __int16 *pRawIndices10 = NULL;			if( SUCCEEDED( pIBuffer10->Map( reinterpret_cast< void** >( &pRawIndices10 ), &stRawIndices10 ) ) )			{				// We now have direct access to the index buffer data				// so we need to lock the incoming, D3DX9, buffer and copy the contents				// across...				unsigned __int16 *pRawIndices9 = NULL;				if( SUCCEEDED( pMesh9->LockIndexBuffer( 0, reinterpret_cast< LPVOID* >( &pRawIndices9 ) ) ) )				{					memcpy_s(	pRawIndices10, 								stRawIndices10, 								pRawIndices9, 								pMesh9->GetNumFaces() * 3 * sizeof( unsigned __int16 ) 							);					// Tidy up					pMesh9->UnlockIndexBuffer( );				}				else				{					ERR_OUT( L"Unable to lock the D3DX9 mesh's index buffer!" );					pIBuffer10->Unmap( );					return E_FAIL;				}				// Tidy up..				pIBuffer10->Unmap( );			}			else			{				ERR_OUT( L"Unable to Map() D3DX10's index buffer!" );				return E_FAIL;			}		}		return S_OK;	}	HRESULT CopyVertexBufferData( ID3DXMesh* pMesh9, ID3DX10Mesh* pMesh10 )	{		if( (NULL == pMesh9) || (NULL == pMesh10) )		{			ERR_OUT( L"Incoming meshes must be valid pointers." );			return E_INVALIDARG;		}		// D3DX10 meshes can have multiple VB's but D3DX9 ones can't		if( 1 != pMesh10->GetVertexBufferCount( ) )		{			ERR_OUT( L"D3DX10 mesh has more than 1 vertex buffer." );			return E_FAIL;		}		CComPtr< ID3DX10MeshBuffer > pVBuffer10;		if( SUCCEEDED( pMesh10->GetVertexBuffer( 0, &pVBuffer10 ) ) )		{			SIZE_T stRawVertices10 = 0;			unsigned __int8 *pRawVertices10 = NULL;			if( SUCCEEDED( pVBuffer10->Map( reinterpret_cast< void** >( &pRawVertices10 ), &stRawVertices10 ) ) )			{				// Now we need to acquire the input lock				unsigned __int8 *pRawVertices9 = NULL;				if( SUCCEEDED( pMesh9->LockVertexBuffer( 0, reinterpret_cast< LPVOID* >( &pRawVertices9 ) ) ) )				{					memcpy_s(								pRawVertices10,								stRawVertices10,								pRawVertices9,								pMesh9->GetNumBytesPerVertex() * pMesh9->GetNumVertices()							);					pMesh9->UnlockVertexBuffer( );				}				else				{					ERR_OUT( L"Failed to lock D3DX9 mesh's vertex buffer!" );					pVBuffer10->Unmap( );					return E_FAIL;				}				pVBuffer10->Unmap( );			}			else			{				ERR_OUT( L"Unable to Map() raw vertex data." );				return E_FAIL;			}		}		else		{			ERR_OUT( L"Unable to acquire the D3DX10 mesh's vertex buffer!" );			return E_FAIL;		}		return S_OK;	}	HRESULT ConfigureAttributeTable( ID3DXMesh* pMesh9, ID3DX10Mesh* pMesh10 )	{		// verify inputs		if( (NULL == pMesh9) || (NULL == pMesh10) )		{			ERR_OUT( L"Both input mesh's must be non-NULL." );			return E_INVALIDARG;		}		DWORD dwInputTableSize = 0;		if( FAILED( pMesh9->GetAttributeTable( NULL, &dwInputTableSize ) ) )		{			ERR_OUT( L"Unable to retrieve the size of the incoming mesh's attribute table" );			return E_FAIL;		}		if( 0 == dwInputTableSize )		{			// The incoming mesh doesn't have an attribute table			INFO_OUT( L"Incoming D3DX9 mesh doesn't have an attribute table, creating a default table." );			D3DX10_ATTRIBUTE_RANGE defTable;			defTable.AttribId		= 0;			defTable.FaceCount		= pMesh10->GetFaceCount( );			defTable.FaceStart		= 0;			defTable.VertexCount	= pMesh10->GetVertexCount( );			defTable.VertexStart	= 0;			if( FAILED( pMesh10->SetAttributeTable( &defTable, 1 ) ) )			{				ERR_OUT( L"Unable to store default attribute table in D3DX10 mesh." );				return E_FAIL;			}		}		else		{			D3DXATTRIBUTERANGE *pInputAttrTable = new D3DXATTRIBUTERANGE[ dwInputTableSize ];			if( FAILED( pMesh9->GetAttributeTable( pInputAttrTable, &dwInputTableSize ) ) )			{				ERR_OUT( L"Unable to retrieve the incoming mesh's attribute table" );				SAFE_DELETE_ARRAY( pInputAttrTable );				return E_FAIL;			}			D3DX10_ATTRIBUTE_RANGE *pNewAttrTable = new D3DX10_ATTRIBUTE_RANGE[ dwInputTableSize ];						for( DWORD i = 0; i < dwInputTableSize; ++i )			{				pNewAttrTable.AttribId		= pInputAttrTable.AttribId;				pNewAttrTable.FaceCount		= pInputAttrTable.FaceCount;				pNewAttrTable.FaceStart		= pInputAttrTable.FaceStart;				pNewAttrTable.VertexCount	= pInputAttrTable.VertexCount;				pNewAttrTable.VertexStart	= pInputAttrTable.VertexStart;			}			SAFE_DELETE_ARRAY( pInputAttrTable );			if( FAILED( pMesh10->SetAttributeTable( pNewAttrTable, static_cast< UINT >( dwInputTableSize ) ) ) )			{				ERR_OUT( L"Unable to copy attribute table from original mesh" );				SAFE_DELETE_ARRAY( pNewAttrTable );				return E_FAIL;			}			SAFE_DELETE_ARRAY( pNewAttrTable );		}		// Create the attribute data		if( FAILED( pMesh10->GenerateAttributeBufferFromTable( ) ) )		{			ERR_OUT( L"Unable to automatically generate the attribute buffer from the attribute table!" );			return E_FAIL;		}		return S_OK;	}};


A few odds and ends:

Globals.h
#ifndef INC_GLOBALS_H#define INC_GLOBALS_H#define WIDEN( w ) WIDEN2( w )#define WIDEN2( w )	L ##w#define INFO_OUT( text ) OutputDebugString( L"(INFO) : " WIDEN( __FUNCTION__ ) L"() - " text L"\n" )#define ERR_OUT( text ) OutputDebugString( L"(ERROR) : " WIDEN( __FUNCTION__ ) L"() - " text L"\n" )#define WARN_OUT( text ) OutputDebugString( L"(WARNING) : " WIDEN( __FUNCTION__ ) L"() - " text L"\n" )#ifndef SAFE_RELEASE	#define SAFE_RELEASE( p ) {if(p){(p)->Release();(p)=NULL;}}#endif#ifndef SAFE_DELETE	#define SAFE_DELETE( p ) {if(p){delete(p);(p)=NULL;}}#endif#ifndef SAFE_DELETE_ARRAY	#define SAFE_DELETE_ARRAY( p ) {if(p){delete[](p);(p)=NULL;}}#endifvoid ComputeSizeAsString( WCHAR *wc, UINT wcLen, SIZE_T bytes );#endif


The following function will create a NULL-REF device so you can use the D3DX9 functions without having to bother about initializing a real D3D9 device...
HRESULT CreateD3D9NullRef( IDirect3DDevice9** ppCreatedDevice ){	CComPtr< IDirect3D9 > pD3D9;	pD3D9.Attach( Direct3DCreate9( D3D_SDK_VERSION ) );	if( NULL == pD3D9 )	{		ERR_OUT( L"Failed to create IDirect3D9 interface" );		return E_FAIL;	}	D3DDISPLAYMODE Mode;	pD3D9->GetAdapterDisplayMode(0, &Mode);	D3DPRESENT_PARAMETERS pp;	ZeroMemory( &pp, sizeof(D3DPRESENT_PARAMETERS) ); 	pp.BackBufferWidth  = 1;	pp.BackBufferHeight = 1;	pp.BackBufferFormat = Mode.Format;	pp.BackBufferCount  = 1;	pp.SwapEffect       = D3DSWAPEFFECT_COPY;	pp.Windowed         = TRUE;	if( FAILED( pD3D9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, DXUTGetHWND(), D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, ppCreatedDevice ) ) )	{		ERR_OUT( L"Unable to create NULLREF device!" );		return E_FAIL;	}	return S_OK;}


If the naming wasn't obvious enough the above code will convert an ID3DXMesh (from D3DX9) to a ID3DX10Mesh (for D3DX10). In both the Beta 2 (June '06 SDK) and RC1 (August '06 SDK) the available D3DX methods seems a little on the brief side. I'm hoping that'll improve. In the meantime I'll be using the above code to allow me to create a source mesh using the entire wealth of the much more mature D3DX9 library yet still have all rendering sent via Direct3D 10 [grin]

For example:
//(Ignoring HRESULT's for simplicity)CComPtr< IDirect3DDevice9 > pDevice9;CreateD3D9NullRef( &pDevice9 );CComPtr< ID3DXMesh > pMesh9;D3DXCreateTeapot( pDevice9, &pMesh9, NULL );// Could throw in call to D3DXComputeTangentFrameEx()// and so on here... do whatever processing is necessary...CComPtr< ID3DX10Mesh > pTeapotMesh;MeshConv::CreateD3DX10MeshFromD3DX9Mesh( pMesh9, &pTeapotMesh, pd3dDevice );pTeapotMesh->CommitToDevice( );// Now use 'pTeapotMesh' for rendering...


Its not been fully tested and I've no idea whether the CDXUTMesh (or whatever its called) has any advantages over this. Basically, I'm using it and I hereby provide it to the community to (ab)use as you see fit - simply because I am that nice [smile]

Till next time...

Jack
0 likes 3 comments

Comments

Will F
Take care. Everyone needs the occasional time off.
September 02, 2006 01:57 PM
noaktree
Noooo!! Stay away from the dark side. Come back to the light. [smile]

See ya when you get back.
September 02, 2006 02:14 PM
zimwman
The code works fine. This was just what i was looking for.

Thanks :)
March 13, 2010 08:23 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement