Jump to content
  • Advertisement
Sign in to follow this  
Drakex

At wit's end with D3DXLoadMeshHierarchyFromXA

This topic is 4793 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm using the December 2004 DX9 SDK. I'm using the following hierarchy allocator class (bare minimum).
class MyAllocator : public ID3DXAllocateHierarchy
{
	STDMETHOD(CreateFrame)(LPCSTR Name, LPD3DXFRAME* ppNewFrame)
	{
		LPD3DXFRAME f=new D3DXFRAME;
		ppNewFrame=&f;
		return D3D_OK;
	}

    STDMETHOD(CreateMeshContainer)(LPCSTR Name, 
        CONST D3DXMESHDATA *pMeshData, 
        CONST D3DXMATERIAL *pMaterials, 
        CONST D3DXEFFECTINSTANCE *pEffectInstances, 
        DWORD NumMaterials, 
        CONST DWORD *pAdjacency, 
        LPD3DXSKININFO pSkinInfo, 
        LPD3DXMESHCONTAINER *ppNewMeshContainer)
	{
		LPD3DXMESHCONTAINER m=new D3DXMESHCONTAINER;
		ppNewMeshContainer=&m;
		return D3D_OK;
	}

    STDMETHOD(DestroyFrame)(LPD3DXFRAME pFrameToFree)
    {
    	return D3D_OK;
    }

    STDMETHOD(DestroyMeshContainer)(LPD3DXMESHCONTAINER pMeshContainerToFree)
    {
    	return D3D_OK;
    }
};


I'm using the following code in my main function.
MyAllocator* alloc=new MyAllocator;
ID3DXAnimationController* ctrl;
D3DXFRAME* f;
HRESULT hr=D3DXLoadMeshHierarchyFromXA("C:\\DX92SDK\\Samples\\Media\\Tiny\\tiny.x",D3DXMESH_MANAGED,gpD3DDevice,alloc,NULL,&f,&ctrl);
if(FAILED(hr))
	DXRuntimeError("Error thing.",hr);

Where gpD3DDevice is simply a pointer to a previously-created D3D device (nothing fancy/special, 640x480 windowed hardware device), and DXRuntimeError() simply displays a message box with a string representation of the HRESULT code. When this is run, the following things happen: 1) MyAllocator::CreateFrame() is called. Once. 2) Immediately after MyAllocator::CreateFrame() returns (the first time), D3DXLoadMeshHierarchyFromXA() returns E_FAIL. E_FAIL is not a documented error code. The following C# code works flawlessly.
using System;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.Samples.DirectX.UtilityToolkit;

namespace SimpleAnimationSample
{
	public class SimpleAnimation
	{
        static int Main() 
        {
            using(Framework sampleFramework = new Framework())
            {
                sampleFramework.Initialize( true, true, true );
                sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, null);

				AnimationAllocation alloc = new AnimationAllocation();
				AnimationRootFrame rootFrame = Mesh.LoadHierarchyFromFile(@"C:\DX92SDK\Samples\Media\Tiny\tiny.x", MeshFlags.Managed, sampleFramework.Device, alloc, null);

                return sampleFramework.ExitCode;
            }
        }
    }

	public class AnimationFrame : Frame { }
	public class AnimationMeshContainer : MeshContainer { }
	public class AnimationAllocation : AllocateHierarchy
    {
        public override Frame CreateFrame(string name) { return new AnimationFrame(); }
        public override MeshContainer CreateMeshContainer(string name, MeshData meshData, ExtendedMaterial[] materials, 
			EffectInstance[] effectInstances, GraphicsStream adjacency, SkinInformation skinInfo) { return new AnimationMeshContainer(); }
    }
}

It is the SimpleAnimation sample whittled down to the same functionality as my sample, loading the same file. What is the difference?! Why doesn't my code work?!

Share this post


Link to post
Share on other sites
Advertisement
You're not actually assigning anything to ppNewFrame in your CreateFrame method.

This:

LPD3DXFRAME f=new D3DXFRAME;
ppNewFrame=&f;


should be:

*ppNewFrame=new D3DXFRAME;


I didn't go over any of the rest of your code, so there may be other problems. But that is the most immediate issue.

Share this post


Link to post
Share on other sites
Well spotted! Unfortunately, although it now runs through each frame and mesh container properly, it now gives me an access violation in the middle of an internal function. So now I'm really lost.

Share this post


Link to post
Share on other sites
Have you tried copying the code from CAllocateHierarchy::CreateFrame() in the C++ version of the SkinnedMesh SDK sample into your MyAllocator::CreateFrame()?

The SkinnedMesh C++ sample works. Its CreateFrame() function fully initialises the members of the newly created D3DXFRAME object; yours doesn't.

It's very likely some part of D3DXLoadMeshHierarchyFromXA() is relying on one or all of the members of D3DXFRAME being valid, or at least initialised after it calls your CreateFrame().


Your "new D3DXFRAME" call will allocate a block of memory equal to sizeof(D3DXFRAME) which will be filled with 0xCD hex ("uninitialised memory") in debug builds.

D3DXFRAME contains pointer members such as "pFrameFirstChild" - I'd guess that the code inside D3DXLoadMeshHierarchyFromXA() does something like:


// create a frame
D3DXFRAME someFrame;
pAlloc->CreateFrame("name", &someFrame);

...

// does this frame have children?
if (someFrame->pFrameFirstChild != NULL)
{
// do whatever
blah = someFrame->pFrameFirstChild->TransformationMatrix
}


I've highlighted the relevent stuff in bold...

- your CreateFrame() has created a block of memory where everything is set to 0xCD
- so the pFrameFirstChild member of the returned object is 0xCDCDCDCD
- 0xCDCDCDCD != NULL
- a pointer of 0xCDCDCDCD doesn't point to anything sensible
- BOOM! - pFrameFirstChild->TransformationMatrix will cause an access violation!



As for why the C# version works? - I'll speculate that a)C# initialises the object to a sensible default for you upon construction, or b)it's still crashing in the same place, but C#'s exception handling is cleaning up automatically and hiding the problem, and/or c)C#'s allocator is initialising the new frame object to 0 (i.e. NULL) rather than using any debug memory values

Share this post


Link to post
Share on other sites
Ahahahaaa! That's it. As a dummy function, I just ZeroMemory'ed the structures.. and sure enough, it works.

Unfortunately, the equivalent code doesn't work in the language I'm trying to get it to work in (D), as it's MAV-ing before any of my callbacks get called. But that's really my problem, as I'm the one trying to use an obscure language to program in the DX API.. ;)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!