void AmbientDiffuseDemo::updateScene(float dt)
{
	mGfxStats->setVertexCount(mTeapot->GetNumVertices());
	mGfxStats->setTriCount(mTeapot->GetNumFaces());
	mGfxStats->update(dt);

	// Get snapshot of input devices.
	gDInput->poll();

	// Check input.
	if( gDInput->keyDown(DIK_W) )	 
		mCameraHeight   += 25.0f * dt;
	if( gDInput->keyDown(DIK_S) )	 
		mCameraHeight   -= 25.0f * dt;

	// Divide by 50 to make mouse less sensitive. 
	mCameraRotationY += gDInput->mouseDX() / 100.0f;
	mCameraRadius    += gDInput->mouseDY() / 25.0f;

	// If we rotate over 360 degrees, just roll back to 0
	if( fabsf(mCameraRotationY) >= 2.0f * D3DX_PI ) 
		mCameraRotationY = 0.0f;

	// Don't let radius get too small.
	if( mCameraRadius < 5.0f )
		mCameraRadius = 5.0f;

	// The camera position/orientation relative to world space can 
	// change every frame based on input, so we need to rebuild the
	// view matrix every frame with the latest changes.
	buildViewMtx();
}
void AmbientDiffuseDemo::updateScene(float dt)
{
    mGfxStats->setVertexCount(mTeapot->GetNumVertices());
    mGfxStats->setTriCount(mTeapot->GetNumFaces());
    mGfxStats->update(dt);

    gDInput->poll();

    if (gDInput->keyDown(DIK_W))
        mCameraHeight += 25.0f * dt;
    if (gDInput->keyDown(DIK_S))
        mCameraHeight -= 25.0f * dt;

    // divide by 50 to make mouse less sensitive
    mCameraRotationY += gDInput->mouseDX() / 50.0f;
    mCameraRadius    += gDInput->mouseDY() / 50.0f;

    if (fabsf(mCameraRotationY) >= 2.0f * D3DX_PI)
        mCameraRotationY = 0.0f;

    if (mCameraRadius < 5.0f)
        mCameraRadius = 5.0f;

    buildViewMtx();
}
HRESULT LoadMesh(IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh)
{
    ID3DXMesh* pMesh = NULL;
    WCHAR str[MAX_PATH];
    HRESULT hr;

    V_RETURN(DXUTFindDXSDKMediaFileCch(str, MAX_PATH, strFileName));

    V_RETURN(D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh));

    DWORD* rgdwAdjacency = NULL;

    if(!(pMesh->GetFVF() & D3DFVF_NORMAL))
    {
        ID3DXMesh* pTempMesh;
        V(pMesh->CloneMeshFVF(pMesh->GetOptions(),
                                pMesh->GetFVF() | D3DFVF_NORMAL,
                                pd3dDevice, &pTempMesh));
        V(D3DXComputeNormals(pTempMesh, NULL));

        SAFE_RELEASE(pMesh);
        pMesh = pTempMesh;
    }
   
    rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3];
    if(rgdwAdjacency == NULL)
        return E_OUTOFMEMORY;
    V(pMesh->GenerateAdjacency(1e-6f, rgdwAdjacency));
    V(pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL));
    delete []rgdwAdjacency;

    *ppMesh = pMesh;

    return S_OK;
}
Exemple #4
0
void CShadow::onTick(float fElapsedTime) {
	for (unsigned int i(0); i < m_vMesh.size(); i++) {
		D3DXVECTOR3 vSun(*m_pSun); D3DXMATRIX mInv;
		D3DXMatrixInverse(&mInv, NULL, m_vMat[i]);
		D3DXVec3TransformCoord(&vSun, &vSun, &mInv);

		ID3DXMesh* pMesh;
		m_vMesh[i]->CloneMeshFVF(m_vMesh[i]->GetOptions(), D3DFVF_XYZ, 
			CDirect3D::getInstance()->GetD3D9Device(), &pMesh);

		D3DXVECTOR3 *pVertices, *pVolume;
		WORD* pIndices;
		pMesh->LockVertexBuffer(NULL, (void**) &pVertices);
		pMesh->LockIndexBuffer(NULL, (void**) &pIndices);
		DWORD dwFaces(pMesh->GetNumFaces());

		WORD* pEdges = new WORD[dwFaces*3*2];
		DWORD dwEdges(0);
		for (DWORD j(0); j < dwFaces; j++) {
			WORD wFace0 = pIndices[j*3];
			WORD wFace1 = pIndices[j*3+1];
			WORD wFace2 = pIndices[j*3+2];
			D3DXVECTOR3 v0 = pVertices[wFace0];
			D3DXVECTOR3 v1 = pVertices[wFace1];
			D3DXVECTOR3 v2 = pVertices[wFace2];
			D3DXVECTOR3 vCross1(v2-v1);
			D3DXVECTOR3 vCross2(v1-v0);
			D3DXVECTOR3 vNormal;
			D3DXVec3Cross(&vNormal, &vCross1, &vCross2);
			if (D3DXVec3Dot(&vNormal, m_pSun) > 0.f) {
				AddEdge(pEdges, dwEdges, wFace0, wFace1);
				AddEdge(pEdges, dwEdges, wFace1, wFace2);
				AddEdge(pEdges, dwEdges, wFace2, wFace0);
			}
		}
		m_dwTriangles[i] = dwEdges*2;
		m_vVB[i]->Lock(0, sizeof(D3DXVECTOR3)*m_dwTriangles[i]*3, (void**) &pVolume, NULL);
		// some (solvable, but expensive) issues here: 
		// (view port related) direction undetermined for segment v1 - v2,
		// so CULL_CW doesn't necessarily mean 'back side'.
		for (DWORD j(0); j < dwEdges; j++) {
			D3DXVECTOR3 v1 = pVertices[pEdges[2*j+0]];	
			D3DXVECTOR3 v2 = pVertices[pEdges[2*j+1]];  
			D3DXVECTOR3 v3 = (v1 - vSun);				
			D3DXVECTOR3 v4 = (v2 - vSun);
			pVolume[j*6] = v3;		
			pVolume[j*6+1] = v1;	
			pVolume[j*6+2] = v4;	// 1 2
			pVolume[j*6+3] = v4;	// |\|
			pVolume[j*6+4] = v1;	// 3 4
			pVolume[j*6+5] = v2;
		}
		m_vVB[i]->Unlock();
		pMesh->UnlockVertexBuffer();
		pMesh->UnlockIndexBuffer();
		Safe_Release(pMesh);
		Safe_Delete_Array(pEdges);
	}
}
Exemple #5
0
void MeshX::BuildSkinnedMesh()
{
	ID3DXMesh* oldMesh = allocMeshHierarchy.GetMeshList().front()->MeshData.pMesh;

	//compute normal
	D3DVERTEXELEMENT9 elements[MAX_FVF_DECL_SIZE];
	oldMesh->GetDeclaration(elements);

	ID3DXMesh* tempMesh = 0;
	ID3DXMesh* tempOpMesh = 0;
	oldMesh->CloneMesh(D3DXMESH_SYSTEMMEM, elements, pDevice, &tempMesh);
	 
	if( !HasNormals(tempMesh) )
		D3DXComputeNormals(tempMesh, 0);

	//optimize the mesh
	DWORD* adj = new DWORD[tempMesh->GetNumFaces()*3];
	ID3DXBuffer* remap = 0;
	tempMesh->GenerateAdjacency(0.00001f, adj);
	tempMesh->Optimize(D3DXMESH_SYSTEMMEM | D3DXMESHOPT_VERTEXCACHE | 
		D3DXMESHOPT_ATTRSORT, adj, 0, 0, &remap, &tempOpMesh);

	SafeRelease(tempMesh);

	// In the .X file (specifically the array DWORD vertexIndices[nWeights]
	// data member of the SkinWeights template) each bone has an array of
	// indices which identify the vertices of the mesh that the bone influences.
	// Because we have just rearranged the vertices (from optimizing), the vertex 
	// indices of a bone are obviously incorrect (i.e., they index to vertices the bone
	// does not influence since we moved vertices around).  In order to update a bone's 
	// vertex indices to the vertices the bone _does_ influence, we simply need to specify
	// where we remapped the vertices to, so that the vertex indices can be updated to 
	// match.  This is done with the ID3DXSkinInfo::Remap method.
	skinInfo->Remap(tempOpMesh->GetNumVertices(), 
		(DWORD*)remap->GetBufferPointer());
	SafeRelease(remap); // Done with remap info.

	DWORD        numBoneComboEntries = 0;
	ID3DXBuffer* boneComboTable      = 0;
	DWORD maxVertInfluences;
	skinInfo->ConvertToIndexedBlendedMesh(tempOpMesh, 0,  
		128, 0, 0, 0, 0, &maxVertInfluences,
		&numBoneComboEntries, &boneComboTable, &this->mesh);

	SafeRelease(tempOpMesh);
	SafeRelease(boneComboTable);
	delete[] adj;
}
Exemple #6
0
//--------------------------------------------------------------------------------------
// This function loads the mesh and ensures the mesh has normals; it also optimizes the 
// mesh for the graphics card's vertex cache, which improves performance by organizing 
// the internal triangle list for less cache misses.
//--------------------------------------------------------------------------------------
HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh )
{
    ID3DXMesh* pMesh = NULL;
    WCHAR str[MAX_PATH];
    HRESULT hr;

    // Load the mesh with D3DX and get back a ID3DXMesh*.  For this
    // sample we'll ignore the X file's embedded materials since we know 
    // exactly the model we're loading.  See the mesh samples such as
    // "OptimizedMesh" for a more generic mesh loading example.
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) );
    V_RETURN( D3DXLoadMeshFromX( str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh ) );

    DWORD* rgdwAdjacency = NULL;

    // Make sure there are normals which are required for lighting
    if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) )
    {
        ID3DXMesh* pTempMesh;
        V( pMesh->CloneMeshFVF( pMesh->GetOptions(),
                                pMesh->GetFVF() | D3DFVF_NORMAL,
                                pd3dDevice, &pTempMesh ) );
        V( D3DXComputeNormals( pTempMesh, NULL ) );

        SAFE_RELEASE( pMesh );
        pMesh = pTempMesh;
    }

    // Optimize the mesh for this graphics card's vertex cache 
    // so when rendering the mesh's triangle list the vertices will 
    // cache hit more often so it won't have to re-execute the vertex shader 
    // on those vertices so it will improve perf.     
    rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3];
    if( rgdwAdjacency == NULL )
        return E_OUTOFMEMORY;
    V( pMesh->GenerateAdjacency( 1e-6f, rgdwAdjacency ) );
    V( pMesh->OptimizeInplace( D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL ) );
    delete []rgdwAdjacency;

    *ppMesh = pMesh;

    return S_OK;
}
//--------------------------------------------------------------------------------------
//메쉬 불러오는 함수
//--------------------------------------------------------------------------------------
HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh )
{
    ID3DXMesh* pMesh = NULL;
    WCHAR str[MAX_PATH];
    HRESULT hr;

    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) );
    V_RETURN( D3DXLoadMeshFromX( str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh ) );

    DWORD* rgdwAdjacency = NULL;

    // mesh에 노말벡터 생성하는 코드
    if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) )
    {
        ID3DXMesh* pTempMesh;
        V( pMesh->CloneMeshFVF( pMesh->GetOptions(),
                                pMesh->GetFVF() | D3DFVF_NORMAL,
                                pd3dDevice, &pTempMesh ) );
        V( D3DXComputeNormals( pTempMesh, NULL ) );

        SAFE_RELEASE( pMesh );
        pMesh = pTempMesh;
    }

	//성능 향상을 도모하고자 인접 정보를 기록
	//각 mesh(삼각형) 정보 테이블을 가지는 형태
	//해당 정보는 pMesh가 가지고 있음
	//각 mesh 정보는 인접할 수 있는 점의 최대 개수가 3개 이내임을 활용해 효율적으로 vertex 운영
    rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3];
    if( rgdwAdjacency == NULL )
        return E_OUTOFMEMORY;
    V( pMesh->GenerateAdjacency( 1e-6f, rgdwAdjacency ) );
	//버텍스 캐쉬를 활용하는 것
    V( pMesh->OptimizeInplace( D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL ) );
    delete []rgdwAdjacency;


	//callback out 변수에 최종 값 저장
    *ppMesh = pMesh;

    return S_OK;
}
bool CMeshBundle::loadMesh( const CResourceId& id, const CResourceId& fullName, CMesh& mesh ) const
{
	// try to load with D3DX
	// obsolete case: .X files
	if( CStringHelper::endsWith( fullName.getUniqueName(), ".x" ) || CStringHelper::endsWith( fullName.getUniqueName(), ".X" ) ) {
		ID3DXBuffer* adjancency = NULL;
		ID3DXBuffer* material = NULL;
		ID3DXBuffer* effects = NULL;
		DWORD matCount;
		ID3DXMesh* dxmesh = NULL;

		HRESULT hres = D3DXLoadMeshFromX(
			fullName.getUniqueName().c_str(),
			D3DXMESH_SYSTEMMEM,
			&CD3DDevice::getInstance().getDevice(),
			&adjancency,
			&material,
			&effects,
			&matCount,
			&dxmesh );
		if( !SUCCEEDED( hres ) )
			return false;
		assert( dxmesh );

		if( adjancency )
			adjancency->Release();
		if( material )
			material->Release();
		if( effects )
			effects->Release();

		//
		// init our mesh

		assert( !mesh.isCreated() );
		// HACK - very limited
		int formatFlags = 0;
		DWORD dxFormat = dxmesh->GetFVF();
		if( dxFormat & D3DFVF_XYZ )
			formatFlags |= CVertexFormat::V_POSITION;
		if( dxFormat & D3DFVF_NORMAL )
			formatFlags |= CVertexFormat::V_NORMAL;
		if( dxFormat & D3DFVF_TEX1 )
			formatFlags |= CVertexFormat::V_UV0_2D;
		CVertexFormat vertFormat( formatFlags );
		// HACK
		int indexStride = 2;

		CD3DVertexDecl* vertDecl = RGET_VDECL( CVertexDesc( vertFormat ) );
		mesh.createResource( dxmesh->GetNumVertices(), dxmesh->GetNumFaces()*3, vertFormat, indexStride, *vertDecl, CMesh::BUF_STATIC );

		//
		// now, copy data into our mesh

		void *dxvb, *dxib;
		dxmesh->LockVertexBuffer( 0, &dxvb );
		dxmesh->LockIndexBuffer( 0, &dxib );
		void* myvb = mesh.lockVBWrite();
		void* myib = mesh.lockIBWrite();

		memcpy( myvb, dxvb, mesh.getVertexCount() * mesh.getVertexStride() );
		memcpy( myib, dxib, mesh.getIndexCount() * mesh.getIndexStride() );
		
		dxmesh->UnlockVertexBuffer();
		dxmesh->UnlockIndexBuffer();
		mesh.unlockVBWrite();
		mesh.unlockIBWrite();

		//
		// create groups

		int ngroups;
		dxmesh->GetAttributeTable( 0, (DWORD*)&ngroups );
		D3DXATTRIBUTERANGE *attrs = new D3DXATTRIBUTERANGE[ngroups];
		dxmesh->GetAttributeTable( attrs, (DWORD*)&ngroups );
		for( int i = 0; i < ngroups; ++i ) {
			const D3DXATTRIBUTERANGE& a = attrs[i];
			mesh.addGroup( CMesh::CGroup( a.VertexStart, a.VertexCount, a.FaceStart, a.FaceCount ) );
		}
		delete[] attrs;

		// release d3dx mesh
		dxmesh->Release();

	} else {

		// our own format
		assert( !mesh.isCreated() );
		bool ok = CMeshSerializer::loadMeshFromFile( fullName.getUniqueName().c_str(), mesh );
		if( !ok )
			return false;
	}
	mesh.computeAABBs();
	CONSOLE.write( "mesh loaded '" + id.getUniqueName() + "'" );
	return true;
}
Exemple #9
0
void GWater::recreateGraphInfo()
{
	HRESULT hr = S_FALSE;

	SeaVertex *pVertextBuffer = NULL;	  //Mesh的顶点缓冲区

	DWORD *pIndexBuffer = NULL;	  //Mesh的索引缓冲区
	ID3DXMesh* mesh = 0;
	hr = D3DXCreateMeshFVF (
		mCellCount * mCellCount * 2,
		( mCellCount + 1 ) * ( mCellCount + 1 ),
		D3DXMESH_32BIT | D3DXMESH_MANAGED, FVFSea,  Content::Device.getD9Device(),
		&mesh
		);

	dDebugMsgBox ( hr, "创建海面Mesh失败!" );

	DWORD dwIndex = 0;

	mesh->LockVertexBuffer ( D3DLOCK_DISCARD, ( void** ) &pVertextBuffer );

	for ( int i = 0; i < mCellCount + 1; i++ )
	{
		for ( int j = 0; j < mCellCount + 1; j++ )
		{
			dwIndex = i * ( mCellCount + 1 ) + j;

			pVertextBuffer[dwIndex].vertex.x = ( j - mCellCount / 2.0f ) * mCellWidth;
			pVertextBuffer[dwIndex].vertex.y = 0;
			pVertextBuffer[dwIndex].vertex.z = ( i - mCellCount / 2.0f ) * mCellWidth;
			pVertextBuffer[dwIndex].u = j / 10.0f;
			pVertextBuffer[dwIndex].v = ( mCellCount - i ) / 10.0f;
		}
	}

	mesh->UnlockVertexBuffer();

	mesh->LockIndexBuffer ( D3DLOCK_DISCARD, ( void** ) &pIndexBuffer );

	DWORD dwBaseIndex = 0;

	for ( int i = 0; i < mCellCount; i++ )
	{
		for ( int j = 0; j < mCellCount; j++ )
		{
			pIndexBuffer[dwBaseIndex + 0] = i * ( mCellCount + 1 ) + j;
			pIndexBuffer[dwBaseIndex + 1] = ( i + 1 ) * ( mCellCount + 1 ) + j;
			pIndexBuffer[dwBaseIndex + 2] = ( i + 1 ) * ( mCellCount + 1 ) + j + 1;

			pIndexBuffer[dwBaseIndex + 3] = i * ( mCellCount + 1 ) + j;
			pIndexBuffer[dwBaseIndex + 4] = ( i + 1 ) * ( mCellCount + 1 ) + j + 1;;
			pIndexBuffer[dwBaseIndex + 5] = i * ( mCellCount + 1 ) + j + 1;

			dwBaseIndex += 6;
		}
	}

	mesh->UnlockIndexBuffer();

	mMeshBufferNode->setMesh ( mesh );
	mMeshBufferNode->setSubCount ( 1 );

	DWORD *pAdj = new DWORD[mesh->GetNumFaces() * 3];

	mesh->GenerateAdjacency ( 1.0f, pAdj );

	delete []pAdj ;
}
/** Merges a set of D3DXMeshes. */
static void MergeD3DXMeshes(
	IDirect3DDevice9* Device,
	TRefCountPtr<ID3DXMesh>& OutMesh,TArray<int32>& OutBaseFaceIndex,const TArray<ID3DXMesh*>& Meshes)
{
	TArray<D3DVERTEXELEMENT9> VertexElements;
	GetD3D9MeshVertexDeclarations(VertexElements);
		
	// Count the number of faces and vertices in the input meshes.
	int32 NumFaces = 0;
	int32 NumVertices = 0;
	for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++)
	{
		NumFaces += Meshes[MeshIndex]->GetNumFaces();
		NumVertices += Meshes[MeshIndex]->GetNumVertices();
	}

	// Create mesh for source data
	VERIFYD3D9RESULT(D3DXCreateMesh(
		NumFaces,
		NumVertices,
		D3DXMESH_SYSTEMMEM,
		(D3DVERTEXELEMENT9*)VertexElements.GetData(),
		Device,
		OutMesh.GetInitReference()
		) );

	// Fill D3DXMesh
	FUtilVertex* ResultVertices;
	uint16*		 ResultIndices;
	::DWORD *		 ResultAttributes;
	OutMesh->LockVertexBuffer(0,(LPVOID*)&ResultVertices);
	OutMesh->LockIndexBuffer(0,(LPVOID*)&ResultIndices);
	OutMesh->LockAttributeBuffer(0, &ResultAttributes);

	int32 BaseVertexIndex = 0;
	int32 BaseFaceIndex = 0;
	for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++)
	{
		ID3DXMesh* Mesh = Meshes[MeshIndex];
				
		FUtilVertex* Vertices;
		uint16*		 Indices;
		::DWORD *		 Attributes;
		Mesh->LockVertexBuffer(0,(LPVOID*)&Vertices);
		Mesh->LockIndexBuffer(0,(LPVOID*)&Indices);
		Mesh->LockAttributeBuffer(0, &Attributes);

		for(uint32 FaceIndex = 0;FaceIndex < Mesh->GetNumFaces();FaceIndex++)
		{
			for(uint32 VertexIndex = 0;VertexIndex < 3;VertexIndex++)
			{
				*ResultIndices++ = BaseVertexIndex + *Indices++;
			}
		}
		OutBaseFaceIndex.Add(BaseFaceIndex);
		BaseFaceIndex += Mesh->GetNumFaces();

		FMemory::Memcpy(ResultVertices,Vertices,Mesh->GetNumVertices() * sizeof(FUtilVertex));
		ResultVertices += Mesh->GetNumVertices();
		BaseVertexIndex += Mesh->GetNumVertices();

		FMemory::Memcpy(ResultAttributes,Attributes,Mesh->GetNumFaces() * sizeof(uint32));
		ResultAttributes += Mesh->GetNumFaces();

		Mesh->UnlockIndexBuffer();
		Mesh->UnlockVertexBuffer();
		Mesh->UnlockAttributeBuffer();
	}

	OutMesh->UnlockIndexBuffer();
	OutMesh->UnlockVertexBuffer();
	OutMesh->UnlockAttributeBuffer();
}
Exemple #11
0
HRESULT HelloShadowVolume::RestoreDeviceObjects()
{
    HRESULT hr;
    IDirect3DDevice8* device;
    hr = m_spD3D->CreateDevice(
             D3DADAPTER_DEFAULT,
             D3DDEVTYPE_HAL,
             m_hWnd,
             D3DCREATE_HARDWARE_VERTEXPROCESSING,
             &m_dpps,
             &device);
    if (FAILED(hr))
    {
        MessageBox(0, L"CreateDevice failed", 0, 0);
        return E_FAIL;
    }
    m_spDevice.reset(device, [](IDirect3DDevice8* device) {
        device->Release();
    });

    m_spDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
    m_spDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    m_spDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE);
    D3DVIEWPORT8 viewport = { 0, 0, m_iWidth, m_iHeight };
    m_spDevice->SetViewport(&viewport);

    D3DXVECTOR3 eye(0.0f, 0.0f, 30.0f);
    D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
    D3DXMatrixLookAtLH(&m_mtView, &eye, &target, &up);

    D3DXMatrixPerspectiveFovLH(&m_mtProj, 0.2*D3DX_PI, (float)m_iWidth / (float)m_iHeight, 1.0f, 100.f);

    m_cPlaneTint = { 0.7f, 0.6f, 0.4f, 1.0f };


    ID3DXMesh* plane;
    //D3DXCreatePolygon(m_spDevice.get(), 2.0f, 4, &plane, NULL);
    CreatePlane(m_spDevice.get(), 15.0f, 10, &plane);
    //D3DXCreateSphere(m_spDevice.get(), 1.0f,20,20, &plane, NULL);

    IDirect3DVertexBuffer8* vb;
    IDirect3DIndexBuffer8* ib;
    plane->GetVertexBuffer(&vb);
    plane->GetIndexBuffer(&ib);
    m_spPlaneVB.reset(vb, [](IDirect3DVertexBuffer8* vb) {
        vb->Release();
    });
    m_spPlaneIB.reset(ib, [](IDirect3DIndexBuffer8* ib) {
        ib->Release();
    });
    m_dwPlaneNumVertices = plane->GetNumVertices();
    m_dwPlaneNumFaces = plane->GetNumFaces();

    plane->Release();

    DWORD decl[] = {
        D3DVSD_STREAM(0),
        D3DVSD_REG(0, D3DVSDT_FLOAT3),
        D3DVSD_REG(3, D3DVSDT_FLOAT3),
        D3DVSD_END()
    };
    hr = CreateVSFromBinFile(m_spDevice.get(), decl, L"plane.vso", &m_dwPlaneVSH);
    if (FAILED(hr))
    {
        MessageBox(0, 0, L"CreateVSFromBinFile failed", 0);
        return E_FAIL;
    }
    hr = CreatePSFromBinFile(m_spDevice.get(), L"plane.pso", &m_dwPlanePSH);
    if (FAILED(hr))
    {
        MessageBox(0, 0, L"CreatePSFromBinFile failed", 0);
        return E_FAIL;
    }

    D3DXMATRIX Rx, Tz;
    D3DXMatrixRotationX(&Rx, D3DX_PI*0.5f);
    D3DXMatrixTranslation(&Tz, 0.0f, -3.0f, 0.0f);
    m_mtPlaneWorld = Rx * Tz;

    ID3DXMesh* occluder;
    CreateOccluder(m_spDevice.get(), &occluder);
    IDirect3DVertexBuffer8* vbOccluder;
    IDirect3DIndexBuffer8* ibOccluder;
    occluder->GetVertexBuffer(&vbOccluder);
    occluder->GetIndexBuffer(&ibOccluder);
    m_spOccluderVB.reset(vbOccluder, [](IDirect3DVertexBuffer8* vb) {
        vb->Release();
    });
    m_spOccluderIB.reset(ibOccluder, [](IDirect3DIndexBuffer8* ib) {
        ib->Release();
    });
    m_dwOccluderNumVertices = occluder->GetNumVertices();
    m_dwOccluderNumFaces = occluder->GetNumFaces();
    occluder->Release();

    hr = CreateVSFromBinFile(m_spDevice.get(), decl, L"occluder.vso", &m_dwOccluderVSH);
    if (FAILED(hr))
    {
        MessageBox(0, 0, L"CreateVSFromBinFile failed", 0);
        return E_FAIL;
    }
    hr = CreatePSFromBinFile(m_spDevice.get(), L"occluder.pso", &m_dwOccluderPSH);
    if (FAILED(hr))
    {
        MessageBox(0, 0, L"CreatePSFromBinFile failed", 0);
        return E_FAIL;
    }
    m_cOccluderTint = { 0.3f, 0.0f, 0.8f, 1.0f };
    D3DXMATRIX Rz, T;
    D3DXMatrixTranslation(&T, 5.1f * cosf(0.5), 0.0f, 5.1f * sinf(0.5));
    D3DXMatrixIdentity(&m_mtVolumeWorld);
    D3DXMatrixRotationZ(&Rz, 0.5f);
    m_mtOccluderWorld = T * Rz;

    ID3DXMesh* volume;
    CreateVolume(m_spDevice.get(), &volume);
    IDirect3DVertexBuffer8* vbVolume;
    IDirect3DIndexBuffer8* ibVolume;
    volume->GetVertexBuffer(&vbVolume);
    volume->GetIndexBuffer(&ibVolume);
    m_spVolumeVB.reset(vbVolume, [](IDirect3DVertexBuffer8* vb) {
        vb->Release();
    });
    m_spVolumeIB.reset(ibVolume, [](IDirect3DIndexBuffer8* ib) {
        ib->Release();
    });
    m_dwVolumeNumVertices = volume->GetNumVertices();
    m_dwVolumeNumFaces = volume->GetNumFaces();
    volume->Release();

    hr = CreateVSFromBinFile(m_spDevice.get(), decl, L"volume.vso", &m_dwVolumeVSH);
    if (FAILED(hr))
    {
        MessageBox(0, 0, L"CreateVSFromBinFile failed", 0);
        return E_FAIL;
    }
    hr = CreatePSFromBinFile(m_spDevice.get(), L"volume.pso", &m_dwVolumePSH);
    if (FAILED(hr))
    {
        MessageBox(0, 0, L"CreatePSFromBinFile failed", 0);
        return E_FAIL;
    }
    m_cVolumeTint = { 0.7f, 0.0f, 0.0f, 1.0f };

    D3DXMATRIX Sx;
    D3DXMatrixIdentity(&m_mtVolumeWorld);
    D3DXMatrixScaling(&Sx, 6.0f, 1.0f, 1.0f);
    D3DXMatrixRotationZ(&Rz, 0.5f);
    m_mtVolumeWorld = Sx * Rz;

    return S_OK;
}
Exemple #12
0
void Terrain::buildSubGridMesh(RECT& R, VertexPNT* gridVerts)
{
	//===============================================================
	// Create the subgrid mesh.
	ID3DXMesh* subMesh = 0;
	D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
	UINT numElems = 0;
	HR(VertexPNT::Decl->GetDeclaration(elems, &numElems));
	HR(D3DXCreateMesh(SubGrid::NUM_TRIS, SubGrid::NUM_VERTS, 
		D3DXMESH_MANAGED, elems, gd3dDevice, &subMesh));


	//===============================================================
	// Build Vertex Buffer.  Copy rectangle of vertices from the
	// grid into the subgrid structure.
	VertexPNT* v = 0;
	HR(subMesh->LockVertexBuffer(0, (void**)&v));
	int k = 0;
	for(int i = R.top; i <= R.bottom; ++i)
	{
		for(int j = R.left; j <= R.right; ++j)
		{
			v[k++] = gridVerts[i*mVertCols+j];
		}
	}

	//===============================================================
	// Compute the bounding box before unlocking the vertex buffer.
	AABB bndBox;
	HR(D3DXComputeBoundingBox((D3DXVECTOR3*)v, subMesh->GetNumVertices(), 
		sizeof(VertexPNT), &bndBox.minPt, &bndBox.maxPt));

	HR(subMesh->UnlockVertexBuffer());


	//===============================================================
	// Build Index and Attribute Buffer.
	// Get indices for subgrid (we don't use the verts here--the verts
	// are given by the parameter gridVerts).
	std::vector<D3DXVECTOR3> tempVerts;
	std::vector<DWORD> tempIndices;
	GenTriGrid(SubGrid::NUM_ROWS, SubGrid::NUM_COLS, mDX, mDZ, 
		D3DXVECTOR3(0.0f, 0.0f, 0.0f), tempVerts, tempIndices);

	WORD* indices  = 0;
	DWORD* attBuff = 0;
	HR(subMesh->LockIndexBuffer(0, (void**)&indices));
	HR(subMesh->LockAttributeBuffer(0, &attBuff));
	for(int i = 0; i < SubGrid::NUM_TRIS; ++i)
	{
		indices[i*3+0] = (WORD)tempIndices[i*3+0];
		indices[i*3+1] = (WORD)tempIndices[i*3+1];
		indices[i*3+2] = (WORD)tempIndices[i*3+2];

		attBuff[i] = 0; // All in subset 0.
	}
	HR(subMesh->UnlockIndexBuffer());
	HR(subMesh->UnlockAttributeBuffer());


	//===============================================================
	// Optimize for the vertex cache and build attribute table.
	DWORD* adj = new DWORD[subMesh->GetNumFaces()*3];
	HR(subMesh->GenerateAdjacency(EPSILON, adj));
	HR(subMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE|D3DXMESHOPT_ATTRSORT,
		adj, 0, 0, 0));
	delete[] adj;

	
	//===============================================================
	// Save the mesh and bounding box.
	mSubGridMeshes.push_back(subMesh);
	mSubGridBndBoxes.push_back(bndBox);
}
Exemple #13
0
void Terrain::buildGeometry()
{
	//===============================================================
	// Create one large mesh for the grid in system memory.

	DWORD numTris  = (mVertRows-1)*(mVertCols-1)*2;
	DWORD numVerts = mVertRows*mVertCols;

	ID3DXMesh* mesh = 0;
	D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
	UINT numElems = 0;
	HR(VertexPNT::Decl->GetDeclaration(elems, &numElems));
	HR(D3DXCreateMesh(numTris, numVerts, 
		D3DXMESH_SYSTEMMEM|D3DXMESH_32BIT, elems, gd3dDevice, &mesh));


	//===============================================================
	// Write the grid vertices and triangles to the mesh.

	VertexPNT* v = 0;
	HR(mesh->LockVertexBuffer(0, (void**)&v));
	
	std::vector<D3DXVECTOR3> verts;
	std::vector<DWORD> indices;
	GenTriGrid(mVertRows, mVertCols, mDX, mDZ, D3DXVECTOR3(0.0f, 0.0f, 0.0f), verts, indices);

	float w = mWidth;
	float d = mDepth;
	for(UINT i = 0; i < mesh->GetNumVertices(); ++i)
	{
		// We store the grid vertices in a linear array, but we can
		// convert the linear array index to an (r, c) matrix index.
		int r = i / mVertCols;
		int c = i % mVertCols;

		v[i].pos   = verts[i];
		v[i].pos.y = mHeightmap(r, c);

		v[i].tex0.x = (v[i].pos.x + (0.5f*w)) / w;
		v[i].tex0.y = (v[i].pos.z - (0.5f*d)) / -d;
	}

	// Write triangle data so we can compute normals.

	DWORD* indexBuffPtr = 0;
	HR(mesh->LockIndexBuffer(0, (void**)&indexBuffPtr));
	for(UINT i = 0; i < mesh->GetNumFaces(); ++i)
	{
		indexBuffPtr[i*3+0] = indices[i*3+0];
		indexBuffPtr[i*3+1] = indices[i*3+1];
		indexBuffPtr[i*3+2] = indices[i*3+2];
	}
	HR(mesh->UnlockIndexBuffer());

	// Compute Vertex Normals.
	HR(D3DXComputeNormals(mesh, 0));

	
	//===============================================================
	// Now break the grid up into subgrid meshes.

	// Find out the number of subgrids we'll have.  For example, if
	// m = 513, n = 257, SUBGRID_VERT_ROWS = SUBGRID_VERT_COLS = 33,
	// then subGridRows = 512/32 = 16 and sibGridCols = 256/32 = 8.
	int subGridRows = (mVertRows-1) / (SubGrid::NUM_ROWS-1);
	int subGridCols = (mVertCols-1) / (SubGrid::NUM_COLS-1);

	for(int r = 0; r < subGridRows; ++r)
	{
		for(int c = 0; c < subGridCols; ++c)
		{
			// Rectangle that indicates (via matrix indices ij) the
			// portion of global grid vertices to use for this subgrid.
			RECT R = 
			{
					c * (SubGrid::NUM_COLS-1),
					r * (SubGrid::NUM_ROWS-1),
				(c+1) * (SubGrid::NUM_COLS-1),
				(r+1) * (SubGrid::NUM_ROWS-1)
			};

			buildSubGridMesh(R, v); 
		}
	}

	HR(mesh->UnlockVertexBuffer());

	ReleaseCOM(mesh); // Done with global mesh.
}
Exemple #14
0
void SkinnedMesh::buildSkinnedMesh(ID3DXMesh* mesh)
{
    //====================================================================
    // First add a normal component and 2D texture coordinates component.

    D3DVERTEXELEMENT9 elements[64];
    UINT numElements = 0;
    VertexPNT::Decl->GetDeclaration(elements, &numElements);

    ID3DXMesh* tempMesh = 0;
    HR(mesh->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &tempMesh));

    if( !hasNormals(tempMesh) )
        HR(D3DXComputeNormals(tempMesh, 0));

    //====================================================================
    // Optimize the mesh; in particular, the vertex cache.
    DWORD* adj = new DWORD[tempMesh->GetNumFaces()*3];
    ID3DXBuffer* remap = 0;
    HR(tempMesh->GenerateAdjacency(EPSILON, adj));
    ID3DXMesh* optimizedTempMesh = 0;
    HR(tempMesh->Optimize(D3DXMESH_SYSTEMMEM | D3DXMESHOPT_VERTEXCACHE |
                          D3DXMESHOPT_ATTRSORT, adj, 0, 0, &remap, &optimizedTempMesh));

    ReleaseCOM(tempMesh); // Done w/ this mesh.
    delete[] adj;         // Done with buffer.

    // In the .X file (specifically the array DWORD vertexIndices[nWeights]
    // data member of the SkinWeights template) each bone has an array of
    // indices which identify the vertices of the mesh that the bone influences.
    // Because we have just rearranged the vertices (from optimizing), the vertex
    // indices of a bone are obviously incorrect (i.e., they index to vertices the bone
    // does not influence since we moved vertices around).  In order to update a bone's
    // vertex indices to the vertices the bone _does_ influence, we simply need to specify
    // where we remapped the vertices to, so that the vertex indices can be updated to
    // match.  This is done with the ID3DXSkinInfo::Remap method.
    HR(mSkinInfo->Remap(optimizedTempMesh->GetNumVertices(),
                        (DWORD*)remap->GetBufferPointer()));
    ReleaseCOM(remap); // Done with remap info.

    //====================================================================
    // The vertex format of the source mesh does not include vertex weights
    // nor bone index data, which are both needed for vertex blending.
    // Therefore, we must convert the source mesh to an "indexed-blended-mesh,"
    // which does have the necessary data.

    DWORD        numBoneComboEntries = 0;
    ID3DXBuffer* boneComboTable      = 0;
    HR(mSkinInfo->ConvertToIndexedBlendedMesh(optimizedTempMesh, D3DXMESH_MANAGED | D3DXMESH_WRITEONLY,
            MAX_NUM_BONES_SUPPORTED, 0, 0, 0, 0, &mMaxVertInfluences,
            &numBoneComboEntries, &boneComboTable, &mSkinnedMesh));

    ReleaseCOM(optimizedTempMesh); // Done with tempMesh.
    ReleaseCOM(boneComboTable); // Don't need bone table.

#if defined(DEBUG) | defined(_DEBUG)
    // Output to the debug output the vertex declaration of the mesh at this point.
    // This is for insight only to see what exactly ConvertToIndexedBlendedMesh
    // does to the vertex declaration.
    D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
    HR(mSkinnedMesh->GetDeclaration(elems));

    OutputDebugString("\nVertex Format After ConvertToIndexedBlendedMesh\n");
    int i = 0;
    while( elems[i].Stream != 0xff ) // While not D3DDECL_END()
    {
        if( elems[i].Type == D3DDECLTYPE_FLOAT1)
            OutputDebugString("Type = D3DDECLTYPE_FLOAT1; ");
        if( elems[i].Type == D3DDECLTYPE_FLOAT2)
            OutputDebugString("Type = D3DDECLTYPE_FLOAT2; ");
        if( elems[i].Type == D3DDECLTYPE_FLOAT3)
            OutputDebugString("Type = D3DDECLTYPE_FLOAT3; ");
        if( elems[i].Type == D3DDECLTYPE_UBYTE4)
            OutputDebugString("Type = D3DDECLTYPE_UBYTE4; ");

        if( elems[i].Usage == D3DDECLUSAGE_POSITION)
            OutputDebugString("Usage = D3DDECLUSAGE_POSITION\n");
        if( elems[i].Usage == D3DDECLUSAGE_BLENDWEIGHT)
            OutputDebugString("Usage = D3DDECLUSAGE_BLENDWEIGHT\n");
        if( elems[i].Usage == D3DDECLUSAGE_BLENDINDICES)
            OutputDebugString("Usage = D3DDECLUSAGE_BLENDINDICES\n");
        if( elems[i].Usage == D3DDECLUSAGE_NORMAL)
            OutputDebugString("Usage = D3DDECLUSAGE_NORMAL\n");
        if( elems[i].Usage == D3DDECLUSAGE_TEXCOORD)
            OutputDebugString("Usage = D3DDECLUSAGE_TEXCOORD\n");
        ++i;
    }
#endif
}
Exemple #15
0
void PropsDemo::buildGrass()
{
	D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
	UINT numElems = 0;
	HR(GrassVertex::Decl->GetDeclaration(elems, &numElems));

	HR(D3DXCreateMesh(NUM_GRASS_BLOCKS*2, NUM_GRASS_BLOCKS*4, D3DXMESH_MANAGED, 
		elems, gd3dDevice, &mGrassMesh));

	GrassVertex* v = 0;
	WORD* k = 0;
	HR(mGrassMesh->LockVertexBuffer(0, (void**)&v));
	HR(mGrassMesh->LockIndexBuffer(0, (void**)&k));

	int indexOffset = 0;

	// Scale down the region in which we generate grass.
	int w = (int)(mTerrain->getWidth() * 0.15f);
	int d = (int)(mTerrain->getDepth() * 0.15f);

	// Randomly generate a grass block (three intersecting quads) around the 
	// terrain in the height range [35, 50] (similar to the trees).
	for(int i = 0; i < NUM_GRASS_BLOCKS; ++i)
	{
		//============================================
		// Construct vertices.

		// Generate random position in region.  Note that we also shift
		// this region to place it in the world.
		float x = (float)((rand() % w) - (w*0.5f)) - 30.0f;
		float z = (float)((rand() % d) - (d*0.5f)) - 20.0f;
		float y = mTerrain->getHeight(x, z); 

		// Only generate grass blocks in this height range.  If the height
		// is outside this range, generate a new random position and 
		// try again.
		if(y < 37.0f || y > 40.0f)
		{
			--i; // We are trying again, so decrement back the index.
			continue;
		}

		float sx = GetRandomFloat(0.75f, 1.25f); 
		float sy = GetRandomFloat(0.75f, 1.25f);
		float sz = GetRandomFloat(0.75f, 1.25f);
		D3DXVECTOR3 pos(x, y, z);
		D3DXVECTOR3 scale(sx, sy, sz);

		buildGrassFin(v, k, indexOffset, pos, scale);
		v += 4;
		k += 6;
	}

	HR(mGrassMesh->UnlockVertexBuffer());
	HR(mGrassMesh->UnlockIndexBuffer());


	// Fill in the attribute buffer (everything in subset 0)
	DWORD* attributeBufferPtr = 0;
	HR(mGrassMesh->LockAttributeBuffer(0, &attributeBufferPtr));
	for(UINT i = 0; i < mGrassMesh->GetNumFaces(); ++i)
		attributeBufferPtr[i] = 0;
	HR(mGrassMesh->UnlockAttributeBuffer());

	DWORD* adj = new DWORD[mGrassMesh->GetNumFaces()*3];
	HR(mGrassMesh->GenerateAdjacency(EPSILON, adj));
	HR(mGrassMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_VERTEXCACHE,
		adj, 0, 0, 0));

	delete [] adj;
}
void LODManager::Render(IDirect3DDevice9 *D3DDevice) {
  const char *meshpath =
    (lod == GRID_FARNEAR ? "landscape\\lod\\farnear\\" :
    (lod == GRID_FARFAR  ? "landscape\\lod\\farfar\\" :
			   "landscape\\lod\\farinf\\"));
  const char *textpath =
    (lod == GRID_FARNEAR ? "landscapelod\\generated\\farnear\\" :
    (lod == GRID_FARFAR  ? "landscapelod\\generated\\farfar\\" :
			   "landscapelod\\generated\\farinf\\"));

  int nativeminx = (GRID_SIZE * 32) + (Constants.Coordinates.x - GridDistantCount.Get());
  int nativeminy = (GRID_SIZE * 32) + (Constants.Coordinates.y - GridDistantCount.Get());
  int nativemaxx = (GRID_SIZE * 32) + (Constants.Coordinates.x + GridDistantCount.Get());
  int nativemaxy = (GRID_SIZE * 32) + (Constants.Coordinates.y + GridDistantCount.Get());

  /* y-axis has flipped rounding */
  nativeminx = (nativeminx / 32) - GRID_SIZE;
  nativeminy = (nativeminy / 32) - GRID_SIZE + 0;
  nativemaxx = (nativemaxx / 32) - GRID_SIZE;
  nativemaxy = (nativemaxy / 32) - GRID_SIZE + 0;

  int gridx = Constants.Coordinates.x / 32;
  int gridy = Constants.Coordinates.y / 32;
  for (int x = (gridx - extend); x <= (gridx + extend); x++)
  for (int y = (gridy - extend); y <= (gridy + extend); y++) {
    /* TODO: try radius, seems it's not a box */
    /* leave out Oblivion's native tiles */
    if ((x >= nativeminx) && (x <= nativemaxx) &&
	(y >= nativeminy) && (y <= nativemaxy))
      continue;
    /* leave out other LOD's inner tiles */
    if ((abs(gridx - x) <= inner) &&
	(abs(gridy - y) <= inner))
      continue;

    /* where are we? */
    const float TileOffset[4] = {x * TILE_DIM, y * TILE_DIM, 0, 0};

    /* filter outside-array coordinates */
    if (((GRID_OFFSET + y) >= 0) && ((GRID_OFFSET + y) < GRID_SIZE) &&
	((GRID_OFFSET + x) >= 0) && ((GRID_OFFSET + x) < GRID_SIZE)) {

      /* never seen, never attempted */
      if (MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) {
	/* TODO: 32 means 32x32 cells, in theory that can be different as well */
	char buf[256]; sprintf(buf, "%02d.%02d.%02d.32", WorldSpace, x * 32, y * 32);
	char pth[256]; strcpy(pth, meshpath); strcat(pth, buf); strcat(pth, ".x");

	/* no textures without mesh, but we can render texture-free */
	if ((MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] =
	    MeshManager::GetSingleton()->LoadPrivateMesh(pth, MR_REGULAR)) != -1) {

	  if (ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) {
	    strcpy(pth, textpath); strcat(pth, buf); strcat(pth, ".dds");
	    ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] =
	      TextureManager::GetSingleton()->LoadPrivateTexture(pth, TR_PLANAR);
	  }

	  if (NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) {
	    strcpy(pth, textpath); strcat(pth, buf); strcat(pth, "_fn.dds");
	    NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] =
	      TextureManager::GetSingleton()->LoadPrivateTexture(pth, TR_PLANAR);
	  }

	  /* put the addresses */
	  ManagedMeshRecord    *mesh = Meshes [lod][GRID_OFFSET + y][GRID_OFFSET + x] =    MeshManager::GetSingleton()->GetMesh   (MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]);
	  ManagedTextureRecord *colr = Colors [lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->GetTexture(ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]);
	  ManagedTextureRecord *norm = Normals[lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->GetTexture(NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]);

	  /* failure to load all resources */
	  if (!mesh || !colr || !norm) {
	    if (mesh) mesh->Release();
	    if (colr) colr->Release();
	    if (norm) norm->Release();

	    MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1;
	    ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1;
	    NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1;

	    continue;
	  }

#if	defined(OBGE_GAMMACORRECTION)
	  /* remember DeGamma for this kind of texture */
	  static const bool PotDeGamma = true;
	  colr->GetTexture()->SetPrivateData(GammaGUID, &PotDeGamma, sizeof(PotDeGamma), 0);
#endif
	}
      }

      /* get the addresses */
      ManagedMeshRecord    *mesh = Meshes [lod][GRID_OFFSET + y][GRID_OFFSET + x];
      ManagedTextureRecord *colr = Colors [lod][GRID_OFFSET + y][GRID_OFFSET + x];
      ManagedTextureRecord *norm = Normals[lod][GRID_OFFSET + y][GRID_OFFSET + x];

      ID3DXMesh *m;
      if (mesh && (m = (ID3DXMesh *)mesh->GetMesh())) {
#if 0
	DWORD FVF  = m->GetFVF();
	DWORD size = m->GetNumBytesPerVertex();
	DWORD numf = m->GetNumFaces();
	DWORD numv = m->GetNumVertices();

	IDirect3DIndexBuffer9 *pIB; m->GetIndexBuffer(&pIB);
	IDirect3DVertexBuffer9 *pVB; m->GetVertexBuffer(&pVB);

	D3DDevice->SetStreamSource(0, pVB, 0, size);
	D3DDevice->SetFVF(FVF);
	D3DDevice->SetTexture(0, colr->GetTexture());
	D3DDevice->SetTexture(1, norm->GetTexture());
	D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numv, 0, numf);
#endif

	D3DDevice->SetTexture(0, colr ? colr->GetTexture() : NULL);
	D3DDevice->SetTexture(1, norm ? norm->GetTexture() : NULL);

	D3DDevice->SetVertexShader(vShader[lod]);
	D3DDevice->SetPixelShader (pShader[lod]);
	D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1);

	m->DrawSubset(0);
      }
    }

    /* water-planes */
    D3DDevice->SetVertexShader(vShaderW);
    D3DDevice->SetPixelShader (pShaderW);
    D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1);

    D3DDevice->SetStreamSource(0, WaterVertex, 0, sizeof(WaterTile));
    D3DDevice->SetFVF(WATERTILEFORMAT);
    D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
  }

  const float TileOffset[4] = {0, 0, 0, 1};

  /* infini-plane */
  D3DDevice->SetVertexShader(vShaderW);
  D3DDevice->SetPixelShader (pShaderW);
  D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1);

  D3DDevice->SetStreamSource(0, InfiniteVertex, 0, sizeof(WaterTile));
  D3DDevice->SetFVF(WATERTILEFORMAT);
  D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}
Exemple #17
0
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    WNDCLASS wc;

    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc = (WNDPROC) MainWindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "xtocmod";
    if (RegisterClass(&wc) == 0)
    {
	MessageBox(NULL,
                   "Failed to register the window class.", "Fatal Error",
                   MB_OK | MB_ICONERROR);
	return NULL;
    }

    DWORD windowStyle = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
                         WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
    g_mainWindow = CreateWindow("xtocmod",
                                "xtocmod",
                                windowStyle,
                                CW_USEDEFAULT,
                                CW_USEDEFAULT,
                                300, 300,
                                NULL,
                                NULL,
                                hInstance,
                                NULL);
    if (g_mainWindow == NULL)
    {
        MessageBox(NULL,
                   "Error creating application window.", "Fatal Error",
                   MB_OK | MB_ICONERROR);
    }

    //ShowWindow(g_mainWindow, SW_SHOW);
    SetForegroundWindow(g_mainWindow);
    SetFocus(g_mainWindow);

    // Initialize D3D
    g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (g_d3d == NULL)
    {
        ShowD3DErrorMessage("Initializing D3D", 0);
        return 1;
    }

    D3DPRESENT_PARAMETERS presentParams;
    ZeroMemory(&presentParams, sizeof(presentParams));
    presentParams.Windowed = TRUE;
    presentParams.SwapEffect = D3DSWAPEFFECT_COPY;
#if 0
    presentParams.BackBufferWidth = 300;
    presentParams.BackBufferHeight = 300;
    presentParams.BackBufferCount = 1;
    presentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    presentParams.Windowed = TRUE;
#endif
    
    HRESULT hr = g_d3d->CreateDevice(D3DADAPTER_DEFAULT,
                                     D3DDEVTYPE_HAL,
                                     g_mainWindow,
                                     D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                     &presentParams,
                                     &g_d3dDev);
    if (FAILED(hr))
    {
        ShowD3DErrorMessage("Creating D3D device", hr);
        //return 1;
    }

    string inputFilename(lpCmdLine);
    string outputFilename(inputFilename, 0, inputFilename.rfind('.'));
    outputFilename += ".cmod";

    ID3DXMesh* mesh = NULL;
    ID3DXBuffer* adjacency = NULL;
    ID3DXBuffer* materialBuf = NULL;
    ID3DXBuffer* effects = NULL;
    DWORD numMaterials;
    
    hr = D3DXLoadMeshFromX(inputFilename.c_str(),
                           0,
                           g_d3dDev,
                           &adjacency,
                           &materialBuf,
                           &effects,
                           &numMaterials,
                           &mesh);
    if (FAILED(hr))
    {
        ShowD3DErrorMessage("Loading mesh from X file", hr);
        return 1;
    }


    DWORD numVertices = mesh->GetNumVertices();
    DWORD numFaces = mesh->GetNumFaces();

    cout << "vertices: " << numVertices << '\n';
    cout << "faces: " << numFaces << '\n';

    cout << "adjacency buffer size: " << adjacency->GetBufferSize() << '\n';

    ofstream meshfile(outputFilename.c_str());

    // Output the header
    meshfile << "#celmodel__ascii\n\n";

    cout << "numMaterials=" << numMaterials << '\n';
    D3DXMATERIAL* materials = reinterpret_cast<D3DXMATERIAL*>(materialBuf->GetBufferPointer());
    for (DWORD mat = 0; mat < numMaterials; mat++)
    {
        meshfile << "material\n";
        meshfile << "diffuse " << materials[mat].MatD3D.Diffuse << '\n';
        //meshfile << "emissive " << materials[mat].MatD3D.Emissive << '\n';
        meshfile << "specular " << materials[mat].MatD3D.Specular << '\n';
        meshfile << "specpower " << materials[mat].MatD3D.Power << '\n';
        meshfile << "opacity " << materials[mat].MatD3D.Diffuse.a << '\n';
        meshfile << "end_material\n\n";
    }

    // Vertex format
    D3DVERTEXELEMENT9 declElements[MAX_FVF_DECL_SIZE];
    hr = mesh->GetDeclaration(declElements);
    if (FAILED(hr))
    {
        ShowD3DErrorMessage("Checking vertex declaration", hr);
        return 1;
    }

    DWORD stride = D3DXGetDeclVertexSize(declElements, 0);

    VertexAttribute vertexMap[VertexAttribute::MaxAttribute];
    CreateVertexAttributeMap(declElements, vertexMap);

    meshfile << "mesh\n\n";

    DumpVertexDescription(vertexMap, meshfile);

    ID3DXMesh* optMesh = NULL;
    ID3DXBuffer* vertexRemap = NULL;
    DWORD* faceRemap = new DWORD[numFaces];
    DWORD* optAdjacency = new DWORD[numFaces * 3];
    hr = mesh->Optimize(D3DXMESHOPT_COMPACT | D3DXMESHOPT_STRIPREORDER,
                        //D3DXMESHOPT_VERTEXCACHE |
                        reinterpret_cast<DWORD*>(adjacency->GetBufferPointer()),
                        optAdjacency,
                        faceRemap,
                        &vertexRemap,
                        &optMesh);
    if (FAILED(hr))
    {
        ShowD3DErrorMessage("Optimize failed: ", hr);
        return 1;
    }
    
    // Attribute table
    DWORD attribTableSize = 0;
    hr = optMesh->GetAttributeTable(NULL, &attribTableSize);
    if (FAILED(hr))
    {
        ShowD3DErrorMessage("Querying attribute table size", hr);
        return 1;
    }

    D3DXATTRIBUTERANGE* attribTable = NULL;
    if (attribTableSize > 0)
    {
        attribTable = new D3DXATTRIBUTERANGE[attribTableSize];
        hr = optMesh->GetAttributeTable(attribTable, &attribTableSize);
        if (FAILED(hr))
        {
            ShowD3DErrorMessage("Getting attribute table", hr);
            return 1;
        }
    }

    cout << "Attribute table size: " << attribTableSize << '\n';
    if (attribTableSize == 1)
    {
        cout << "Attribute id: " << attribTable[0].AttribId << '\n';
    }

    if (!DumpMeshVertices(optMesh, vertexMap, stride, meshfile))
        return 1;
    
    // output the indices
    for (DWORD attr = 0; attr < attribTableSize; attr++)
    {
        StripifyMeshSubset(optMesh, attr, meshfile);
    }
    meshfile << "\nend_mesh\n";

#if 0
    IDirect3DIndexBuffer9* indices = NULL;
    hr = mesh->GetIndexBuffer(&indices);
#endif

#if 0
    // No message loop required for this app
    MSG msg;
    GetMessage(&msg, NULL, 0u, 0u);
    while (msg.message != WM_QUIT)
    {
        GetMessage(&msg, NULL, 0u, 0u);
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
#endif

    return 0;
}
Exemple #18
0
void CMesh3D::DrawMyMesh()
{
	D3DXMATRIX  wvp;
	if ( m_pMesh )
	{
		wvp = m_MatrixWorld * m_MatrixView * m_MatrixProjection;
		if ( g_DeviceD3D.m_pConstTableVS[Diffuse] )
		{
			g_DeviceD3D.m_pConstTableVS[Diffuse] -> SetMatrix( g_pD3DDevice, "mat_mvp",   &wvp );
			g_DeviceD3D.m_pConstTableVS[Diffuse] -> SetMatrix( g_pD3DDevice, "mat_world", &m_MatrixWorld );
			g_DeviceD3D.m_pConstTableVS[Diffuse] -> SetVector( g_pD3DDevice, "vec_light", &Light );
			g_DeviceD3D.m_pConstTablePS[Diffuse] -> SetFloat(  g_pD3DDevice, "diffuse_intensity", Diffuse_intensity );	
			g_DeviceD3D.m_pConstTablePS[Diffuse] -> SetFloat(  g_pD3DDevice, "Alpha", m_Alpha );	
		}
		// устанавливаем шейдеры
		g_pD3DDevice->SetVertexShader( g_DeviceD3D.m_pVertexShader[Diffuse] );
		g_pD3DDevice->SetPixelShader(  g_DeviceD3D.m_pPixelShader [Diffuse] );

		g_pD3DDevice->SetStreamSource( 0, m_VertexBuffer, 0, m_SizeFVF );
		g_pD3DDevice->SetIndices( m_IndexBuffer );
		for ( int i = 0; i < m_TexturCount; ++i )
		{
			g_pD3DDevice -> SetMaterial( &m_pMeshMaterial[i] );
			g_pD3DDevice -> SetTexture( 0, m_pMeshTextura[i] );
			//m_pMesh -> DrawSubset(i);
		}
		g_pD3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, m_pMesh->GetNumVertices(), 0, m_pMesh->GetNumFaces() ); 
	}
}
Exemple #19
0
//--------------------------------------------------------------------------------------
HRESULT CMeshLoader::Create( IDirect3DDevice9* pd3dDevice, const WCHAR* strFilename )
{
    HRESULT hr;
    WCHAR str[ MAX_PATH ] = {0};

    // Start clean
    Destroy();

    // Store the device pointer
    m_pd3dDevice = pd3dDevice;

    // Load the vertex buffer, index buffer, and subset information from a file. In this case, 
    // an .obj file was chosen for simplicity, but it's meant to illustrate that ID3DXMesh objects
    // can be filled from any mesh file format once the necessary data is extracted from file.
    
    //V_RETURN( LoadGeometryFromOBJ( strFilename ) );
    V_RETURN( LoadGeometryFromOBJ_Fast( strFilename ) );

    // Set the current directory based on where the mesh was found
    WCHAR wstrOldDir[MAX_PATH] = {0};
    GetCurrentDirectory( MAX_PATH, wstrOldDir );
    SetCurrentDirectory( m_strMediaDir );

    // Load material textures
    for( int iMaterial = 0; iMaterial < m_Materials.GetSize(); iMaterial++ )
    {
        Material* pMaterial = m_Materials.GetAt( iMaterial );
        if( pMaterial->strTexture[0] )
        {
            // Avoid loading the same texture twice
            bool bFound = false;
            for( int x = 0; x < iMaterial; x++ )
            {
                Material* pCur = m_Materials.GetAt( x );
                if( 0 == wcscmp( pCur->strTexture, pMaterial->strTexture ) )
                {
                    bFound = true;
                    pMaterial->pTexture = pCur->pTexture;
                    break;
                }
            }

            // Not found, load the texture
            if( !bFound )
            {
                V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, pMaterial->strTexture ) );
                V_RETURN( D3DXCreateTextureFromFile( pd3dDevice, pMaterial->strTexture,
                                                     &( pMaterial->pTexture ) ) );
                int a = 0;
            }
        }
    }

    // Restore the original current directory
    SetCurrentDirectory( wstrOldDir );

    // Create the encapsulated mesh
    ID3DXMesh* pMesh = NULL;
    V_RETURN( D3DXCreateMesh( m_Indices.GetSize() / 3, m_Vertices.GetSize(),
                              D3DXMESH_MANAGED | D3DXMESH_32BIT, VERTEX_DECL,
                              pd3dDevice, &pMesh ) );

    // Copy the vertex data
    VERTEX* pVertex;
    V_RETURN( pMesh->LockVertexBuffer( 0, ( void** )&pVertex ) );
    memcpy( pVertex, m_Vertices.GetData(), m_Vertices.GetSize() * sizeof( VERTEX ) );
    pMesh->UnlockVertexBuffer();
    m_Vertices.RemoveAll();

    // Copy the index data
    DWORD* pIndex;
    V_RETURN( pMesh->LockIndexBuffer( 0, ( void** )&pIndex ) );
    memcpy( pIndex, m_Indices.GetData(), m_Indices.GetSize() * sizeof( DWORD ) );
    pMesh->UnlockIndexBuffer();
    m_Indices.RemoveAll();

    // Copy the attribute data
    DWORD* pSubset;
    V_RETURN( pMesh->LockAttributeBuffer( 0, &pSubset ) );
    memcpy( pSubset, m_Attributes.GetData(), m_Attributes.GetSize() * sizeof( DWORD ) );
    pMesh->UnlockAttributeBuffer();
    m_Attributes.RemoveAll();

    // Reorder the vertices according to subset and optimize the mesh for this graphics 
    // card's vertex cache. When rendering the mesh's triangle list the vertices will 
    // cache hit more often so it won't have to re-execute the vertex shader.
    DWORD* aAdjacency = new DWORD[pMesh->GetNumFaces() * 3];
    if( aAdjacency == NULL )
        return E_OUTOFMEMORY;

    V( pMesh->GenerateAdjacency( 1e-6f, aAdjacency ) );
    V( pMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, aAdjacency, NULL, NULL, NULL ) );

    SAFE_DELETE_ARRAY( aAdjacency );
    m_pMesh = pMesh;

    return S_OK;
}
Exemple #20
0
VCNNode* D3DConverter::ConvertMesh(const std::wstring& name, LPD3DXMESHCONTAINER baseMeshContainer,
	D3DXFRAME* frameRoot, ID3DXAnimationController* animController, LPDIRECT3DDEVICE9 device)
{
	MultiAnimMC* meshContainer = static_cast<MultiAnimMC*>(baseMeshContainer);
	ID3DXMesh* systemMesh = meshContainer->MeshData.pMesh;

	// Load vertex caches
	//
	DWORD meshFVF = systemMesh->GetFVF();
	size_t vertexCount = systemMesh->GetNumVertices();
	const DWORD stride = D3DXGetFVFVertexSize( meshFVF );
	const DWORD normalStride = D3DXGetFVFVertexSize( D3DFVF_NORMAL );
	const DWORD diffuseStride = D3DXGetFVFVertexSize( D3DFVF_DIFFUSE );
	const DWORD textureStride = D3DXGetFVFVertexSize( D3DFVF_TEX1 );

	std::vector<VCNFloat> vtPositionBuffer( vertexCount * kCacheStrides[VT_POSITION] );
	std::vector<VCNFloat> vtBlendWeights( vertexCount * kCacheStrides[VT_BLENDWEIGHTS] ); //TODO Verify the size of this shit
	std::vector<DWORD> vtBlendIndices( vertexCount * kCacheStrides[VT_BLENDINDICES] ); //TODO Verify the size of this shit

	std::vector<VCNFloat> vtNormalBuffer( vertexCount * kCacheStrides[VT_LIGHTING] );
	std::vector<VCNFloat> vtTextureBuffer( vertexCount * kCacheStrides[VT_DIFFUSE_TEX_COORDS] );

	VCNFloat* vtPositionBuf = &vtPositionBuffer[0];
	VCNFloat* vtBlendWeightBuf = &vtBlendWeights[0];
	DWORD* vtBlendIndicesBuf = &vtBlendIndices[0];

	VCNFloat* vtNormalBuf = &vtNormalBuffer[0];
	VCNFloat* vtTextureBuf = &vtTextureBuffer[0];

	BYTE* vbptr = NULL;
	BYTE* vblineptr = NULL;
	systemMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&vblineptr);

	DWORD positionBlendAndIndicesStride = GetPositionStride(meshFVF);

	for(VCNUInt i = 0; i < vertexCount; ++i)
	{
		vbptr = vblineptr;

		if ( ContainsPositionInformation(meshFVF) )
		{
			// Read position
			float* posData = (float*)vbptr;
			*vtPositionBuf = posData[0]; vtPositionBuf++;
			*vtPositionBuf = posData[1]; vtPositionBuf++;
			*vtPositionBuf = posData[2]; vtPositionBuf++;

			if (ContainsBlending(meshFVF))
			{
				// Get blend weights
				size_t blendCount = (positionBlendAndIndicesStride / 4) - 3 - 1; // -3 to remove xyz, -1 to remove indices which come after
				for(size_t i = 0; i < blendCount; ++i)
				{
					*vtBlendWeightBuf = posData[3 + i]; vtBlendWeightBuf++;
				}
				vtBlendWeightBuf += 4 - blendCount; //each item is an array of 4 floats

				// Get blend indices
				// TODO SKIN Check the format we have to send this data as.
				if ( ContainsFlag(meshFVF, D3DFVF_LASTBETA_UBYTE4) )
				{
					*vtBlendIndicesBuf = ((DWORD*)vbptr)[3 + blendCount]; vtBlendIndicesBuf++;
				}
			}

			vbptr += positionBlendAndIndicesStride;
		}
		else
		{
			VCN_ASSERT_FAIL( VCNTXT("Mesh FVF not supported (no vertex position) [FVF = %d, stride = %d]"), meshFVF, stride );
		}

		// Read normal
		if ( ContainsFlag(meshFVF, D3DFVF_NORMAL) )
		{
			D3DXVECTOR3* normal = (D3DXVECTOR3*)(vbptr);
			*vtNormalBuf = normal->x; vtNormalBuf++;
			*vtNormalBuf = normal->y; vtNormalBuf++;
			*vtNormalBuf = normal->z; vtNormalBuf++;

			// Set default diffuse color
			std::fill(vtNormalBuf, vtNormalBuf+3, 1.0f); vtNormalBuf += 3;

			vbptr += normalStride;
		}
		else
		{
			VCN_ASSERT_FAIL( VCNTXT("Mesh FVF not supported (no normals) [FVF = %d, stride = %d]"), meshFVF, stride );
		}

		if ( ContainsFlag(meshFVF, D3DFVF_DIFFUSE) ) vbptr += diffuseStride;

		// Read texcoords
		// the check with D3DFVF_TEX0 is pretty useless as it's always true... the flag value is 0...
		if ( ContainsFlag(meshFVF, D3DFVF_TEX0) || ContainsFlag(meshFVF, D3DFVF_TEX1) )
		{
			float* texCoords = (float*)(vbptr);
			*vtTextureBuf = texCoords[0]; vtTextureBuf++;
			*vtTextureBuf = texCoords[1]; vtTextureBuf++;

			vbptr += textureStride;
		}
		else
		{
			VCN_ASSERT_FAIL( VCNTXT("Mesh FVF not supported (no texture coordinates) [FVF = %d, stride = %d]"), meshFVF, stride );
		}

		vblineptr += stride;
	}
	systemMesh->UnlockVertexBuffer();

	VCND3D9* renderer = VCNRenderCore::GetInstance()->Cast<VCND3D9>();

	// Generate cache resources that will be bind to Vicuna's meshes
	VCNResID positionCache = renderer->CreateCache(VT_POSITION, &vtPositionBuffer[0], vertexCount * kCacheStrides[VT_POSITION]);
	VCNResID lightingCache = renderer->CreateCache(VT_LIGHTING, &vtNormalBuffer[0], vertexCount * kCacheStrides[VT_LIGHTING]);
	VCNResID textureCache = renderer->CreateCache(VT_DIFFUSE_TEX_COORDS, &vtTextureBuffer[0], vertexCount * kCacheStrides[VT_DIFFUSE_TEX_COORDS]);

	VCNResID blendWeightCache = renderer->CreateCache(VT_BLENDWEIGHTS, &vtBlendWeights[0], vertexCount * kCacheStrides[VT_BLENDWEIGHTS]);
	VCNResID blendIndiceCache = renderer->CreateCache(VT_BLENDINDICES, &vtBlendIndices[0], vertexCount * kCacheStrides[VT_BLENDINDICES]);

	// Get model faces
	//
	VCNUShort* ibptr = 0;
	std::vector<VCNUShort> indices( systemMesh->GetNumFaces() * 3 );
	systemMesh->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&ibptr);
	for(VCNUInt i = 0; i < systemMesh->GetNumFaces(); i++)
	{
		indices[(i * 3) + 0] = *(ibptr++);
		indices[(i * 3) + 1] = *(ibptr++);
		indices[(i * 3) + 2] = *(ibptr++);
	}
	systemMesh->UnlockIndexBuffer();

	// Load materials
	//
	std::vector<VCNResID> materialIDS;
	D3DXMATERIAL* d3dxMaterials = meshContainer->pMaterials;
	for (DWORD i = 0; i < meshContainer->NumMaterials; ++i)
	{
		VCNResID materialID = kInvalidResID;

		// Create the texture if it exists - it may not
		if ( d3dxMaterials[i].pTextureFilename )
		{
			VCNResID textureID = kInvalidResID;

			VCNString texturePath = VCNTXT("Textures/");
			texturePath += VCN_A2W(d3dxMaterials[i].pTextureFilename);

			// Check if the texture is already loaded
			VCND3D9Texture* resTexture = VCNResourceCore::GetInstance()->GetResource<VCND3D9Texture>(texturePath);
			if ( !resTexture )
			{
				textureID = VCNMaterialCore::GetInstance()->CreateTexture(texturePath);
				VCN_ASSERT_MSG( textureID != kInvalidResID, VCNTXT("Can't load texture %s"), texturePath.c_str() );
			}
			else
			{
				textureID = resTexture->GetResourceID();
			}

			VCNMaterial* material = new VCNMaterial();
			const VCNString materialName = StringBuilder() << name << VCNTXT("_material_") << i;
			material->SetName( materialName );
			VCNColor ambient = VCNColor((const VCNFloat*)&d3dxMaterials[i].MatD3D.Ambient);
			ambient.a = 1.0f;
			ambient += VCNColor(0.5f, 0.5f, 0.5f, 0);

			material->SetAmbientColor( ambient );
			material->SetDiffuseColor( VCNColor((const VCNFloat*)&d3dxMaterials[i].MatD3D.Diffuse) );
			material->SetSpecularColor( VCNColor((const VCNFloat*)&d3dxMaterials[i].MatD3D.Specular) );
			material->SetSpecularPower( d3dxMaterials[i].MatD3D.Power );

			VCNEffectParamSet& params = material->GetEffectParamSet();
			params.SetEffectID( eidSkinned );
			params.AddResource( VCNTXT("DiffuseTexture"), textureID );

			// Add material as a resource.
			materialID = VCNResourceCore::GetInstance()->AddResource( material->GetName(), material );
		}

		materialIDS.push_back( materialID );
	}

	// Get the model attribute table with which we will instantiate has many mesh.
	//
	DWORD attribTableSize;
	std::vector<D3DXATTRIBUTERANGE> attribTable;
	HRESULT hr = systemMesh->GetAttributeTable( 0, &attribTableSize );
	if ( FAILED(hr) )
		return 0;
	attribTable.resize( attribTableSize );
	hr = systemMesh->GetAttributeTable( &attribTable[0], &attribTableSize );
	if ( FAILED(hr) )
		return 0;

	// Set the root node
	VCNNode* rootNode = attribTableSize > 1 ?  VCNNodeCore::GetInstance()->CreateNode<VCNNode>() : 
		VCNNodeCore::GetInstance()->CreateNode<VCNRenderNode>();

	rootNode->SetTag( StringBuilder() << name << VCNTXT("_Root") );

	// For each attribute, we get the material texture
	for (DWORD i = 0; i < attribTableSize; ++i)
	{
		VCNRenderNode* partNode = attribTableSize == 1 ? 
			safe_pointer_cast<VCNRenderNode*>( rootNode ) : 
		VCNNodeCore::GetInstance()->CreateNode<VCNRenderNode>();

		const VCNString partNodeName = StringBuilder() << name << VCNTXT("_Part_") << i;
		partNode->SetTag( partNodeName );

		VCNMesh* partMesh = new VCNMesh();
		partMesh->SetCacheID(VT_POSITION, positionCache); //SKIN do this for blend weights and blend indices
		partMesh->SetCacheID(VT_LIGHTING, lightingCache);
		partMesh->SetCacheID(VT_DIFFUSE_TEX_COORDS, textureCache);
		partMesh->SetCacheID(VT_BLENDWEIGHTS, blendWeightCache);
		partMesh->SetCacheID(VT_BLENDINDICES, blendIndiceCache);
		partMesh->SetPrimitiveType(PT_TRIANGLELIST);

		partMesh->SetBoneInfluenceCount( meshContainer->m_dwMaxNumFaceInfls );
		size_t numBones = meshContainer->pSkinInfo == nullptr ? 0 : meshContainer->pSkinInfo->GetNumBones();
		if (numBones > 0)
		{
			auto offsets = std::vector<Matrix4>(numBones);
			std::transform( std::begin(meshContainer->m_amxBoneOffsets), std::end(meshContainer->m_amxBoneOffsets), std::begin(offsets), [](const D3DXMATRIX& mat)
			{
				return Matrix4( (VCNFloat*)mat.m );
			});

			partMesh->SetBoneOffsets( std::move(offsets) );

			LPD3DXBONECOMBINATION boneCombination = reinterpret_cast<LPD3DXBONECOMBINATION>( 
				meshContainer->m_pBufBoneCombos->GetBufferPointer() );

			size_t numPaletteEntries = meshContainer->m_dwNumPaletteEntries;

			std::vector<size_t> matriceIndexes;

			for(size_t paletteIndex = 0; paletteIndex < numPaletteEntries; ++paletteIndex)
			{
				size_t matIndex = boneCombination[i].BoneId[paletteIndex];
				if ( matIndex == std::numeric_limits<size_t>::max())
					continue;

				matriceIndexes.push_back(matIndex);
			}

			partMesh->SetMatrixPaletteIndexes(matriceIndexes);
		}

		const DWORD partFaceCount = attribTable[i].FaceCount;
		const void* partFaceBufferStart = &indices[attribTable[i].FaceStart * 3];
		const VCNResID indexCacheID = renderer->CreateCache(VT_INDEX, partFaceBufferStart, partFaceCount * 3 * kCacheStrides[VT_INDEX]);
		partMesh->SetFaceCount( attribTable[i].FaceCount );
		partMesh->SetFaceCache( indexCacheID );

		// Compute bounding sphere
		float radius;
		D3DXVECTOR3 center;
		D3DXComputeBoundingSphere( (D3DXVECTOR3*)(&vtPositionBuffer[0] + attribTable[i].VertexStart * 3), 
			attribTable[i].VertexCount, stride, &center, &radius );
		VCNSphere modelBoundSphere( radius, V2V<Vector3>(center) );
		partMesh->SetBoundingSphere( modelBoundSphere );

		// Add mesh resource
		const VCNString partMeshName = StringBuilder() << name << VCNTXT("_part_") << i;
		const VCNResID partMeshID = VCNResourceCore::GetInstance()->AddResource( partMeshName, partMesh );

		// Set model part node attributes
		partNode->SetMeshID( partMeshID );
		if (animController && numBones > 0)
		{
			partNode->AddComponent( new VCND3DAnimator(partMeshID, animController, frameRoot, meshContainer->m_apmxBonePointers) );
		}

		size_t index = attribTable[i].AttribId;
		index = index >= materialIDS.size() ? materialIDS.size() - 1 : index;

		partNode->SetMaterialID( materialIDS[index] );

		// Add children to root
		if ( attribTableSize > 1 )
		{
			rootNode->AttachChild( partNode->GetNodeID() );
		}
	}

	return rootNode;
}