Manually loading in .X files

Started by
3 comments, last by dev578 16 years, 1 month ago
I am trying to manually load in a .X file so I can eventually parse my own custom data. I am also trying to load skeletal animation information, and I want to use the information independently of the DirectX API. As in, I just want to use DirectX to load in the information from a .X file, because I don't want to write a parser dealing with low level file I/O. I want to use the loaded information in my own systems, independent of the DirectX API. So I came across D3DXLoadMeshFromXof, and it seems to be what I want. However, the call to D3DXLoadMeshFromXof crashes, giving me an access violation reading location 0x0. I wrote an equivalent D3DXLoadMeshFromX function, and it works. I hate asking questions like this, but the documentation on this function is very limited at best. Does anyone have any experience with this, or have any idea why this would be happening?

#include "MainGame.h"

#include <rmxftmpl.h>
#include <rmxfguid.h>
#pragma comment (lib, "dxguid.lib")

#include "D3DRenderer.h"
#include "RendererGeneral.h"

#define MANUAL_LOADING

CMainGame::CMainGame()
{
	m_bFocus = false;
	m_pMesh = 0;
}

CMainGame::~CMainGame()
{

}

bool CMainGame::Initialize(HWND hWnd, HINSTANCE hInstance, BOOL bWindowed)
{
	if (CD3DRenderer::GetInstance()->Init(hWnd, bWindowed) == FALSE)
	{
		MessageBox(NULL, "Failed to initialize renderer", "Error", MB_OK);
		return false;
	}

	// Set the world matrix
	D3DXMATRIX matWorld;
	D3DXMatrixIdentity(&matWorld);
	CD3DRenderer::GetInstance()->SetWorld(matWorld);

	// Set the camera back so we can view the mesh
	D3DXMATRIX matView;
	D3DXVECTOR3 vEye(0.0f, 0.0f, -5.0f);
	D3DXVECTOR3 vAt(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&matView, &vEye, &vAt, &vUp);
	CD3DRenderer::GetInstance()->SetView(matView);

	// Set the projection matrix
	D3DXMATRIX matProj;
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4.0f, 4.0f / 3.0f, 1.0f, 1000.0f);
	CD3DRenderer::GetInstance()->SetProj(matProj);

	// Set the clear color
	tColor3f clrColor(0.0f, 0.0f, 1.0f);
	CD3DRenderer::GetInstance()->SetClearColor(clrColor);

#ifdef MANUAL_LOADING

	// Try to parse our .X file manually
	ID3DXFile* pDXFile = NULL;
	ID3DXFileEnumObject* pDXEnum = NULL;
	ID3DXFileData* pDXData = NULL;
	SIZE_T nChildren, i;
	GUID id;

	// Create the file object
	if (FAILED(D3DXFileCreate(&pDXFile)))
		return false;

	// Register the common templates
	if (FAILED(pDXFile->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
	{
		pDXFile->Release();
		return false;
	}

	// Create an enumeration object
	if (FAILED(pDXFile->CreateEnumObject("tiger.x", D3DXF_FILELOAD_FROMFILE, &pDXEnum)))
	{
		pDXFile->Release();
		return false;
	}

	if (SUCCEEDED(pDXEnum->GetChildren(&nChildren)))
	{
		for (i = 0; i < nChildren; ++i)
		{
			if (FAILED(pDXEnum->GetChild(i, &pDXData)))
				break;

			if (FAILED(pDXData->GetType(&id)))
			{
				pDXData->Release();
				break;
			}

			if (id == TID_D3DRMMesh)
			{
				if (SUCCEEDED(D3DXLoadMeshFromXof(pDXData, 0, CD3DRenderer::GetInstance()->GetDevice(), 0, 0, 0, 0, &m_pMesh)))
				{
					pDXData->Release();
					break;
				}
			}

			pDXData->Release();
		}
	}

	// Release used COM objects
	pDXEnum->Release();
	pDXFile->Release();

#else

	if (FAILED(D3DXLoadMeshFromX("tiger.x", 0, CD3DRenderer::GetInstance()->GetDevice(), 0, 0, 0, 0, &m_pMesh)))
	{
		MessageBox(NULL, "Failed to load mesh", "Error", MB_OK);
		return false;
	}

#endif

	return true;
}

bool CMainGame::GameLoop()
{
	if (CD3DRenderer::GetInstance()->RenderBegin(TRUE, TRUE, TRUE) == FALSE)
	{
		MessageBox(NULL, "Failed to begin rendering", "Error", MB_OK);
		return false;
	}

	if (m_pMesh)
		m_pMesh->DrawSubset(0);

	CD3DRenderer::GetInstance()->RenderEnd();

	return true;
}

void CMainGame::Shutdown()
{
	if (m_pMesh)
		m_pMesh->Release();
	m_pMesh = 0;

	CD3DRenderer::GetInstance()->Shutdown();
	CD3DRenderer::DeleteInstance();
}

Thank you for your time, Dev578
Advertisement
Have you run the code that crashes with the debug runtimes? They're usually pretty good at spitting out informational messages to the Visual Studio 'output' window explaining why things aren't working. Could be that it doesn't like the data format you're providing...

Also, which DXSDK are you using? I suspect the .X routines won't have changed much over the last few years, but it can sometimes be worth using a more up-to-date build to ensure that it wasn't a genuine bug on MS's part that they've since fixed.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Thanks for the reply.

Yes, I have run the code with the debug runtimes. It doesn't tell me anything about why it failed. It actually crashes somewhere in the D3DXLoadMeshFromXof function.

I was using the August 2007 SDK, but I just upgraded to November 2007. The crash is the same with both of them.

If the debugger is working correctly, it is crashing in this function from guiddef.h:

__inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
return !memcmp(&rguid1, &rguid2, sizeof(GUID));
}

rguid2 appears to be invalid, as it has ???'s throughout the data fields. This is the same behavior with both the SDK versions I have used.

Any ideas?

-Dev578

[EDIT] Oh, and what do you mean by data format?
By data format I mean that the file data you're passing contains unexpected data that causes it to trip up. Really you'd hope it gives you a proper error message in this case, but could well be that you've just hit a fringe case or that D3DXLoadMeshFromXof() isn't implemented all that robustly.

Good old Tiger.x should be fine, but if you can run your code against a wider set of .x format files then that'd be a good thing. Then you can either prove/eliminate the source data as being the problem.

Also, the docs I have don't specify "can be NULL" for some of the parameters you're setting to 0. Might be worth throwing in some code that provides valid pointers here to see if your access violation is D3DXLoadMeshFromXof() being stupid and trusting your inputs to be valid pointers...

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

That was it! Apparently, you cannot pass NULL for adjacency information. However, you can for materials, number of materials, and effect instances. This is kind of dumb, but you are correct in saying the documentation never says you can pass NULL. It's a little annoying that D3DXLoadMeshFromX will allow you to pass NULL for everything, but D3DXLoadMeshFromXof requires adjacency information.

Thank you,

-Dev578

This topic is closed to new replies.

Advertisement