This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Simple X File Wrapper For Loading Data
  Submitted by



This is my first post to COTD, in fact it’s my first post to Flipcode ever. Ok, I recently wrote a small proof of concept application and in doing so I needed to load models from Microsoft’s X flies. After working with the API directly for about a day I found it very redundant and not easy to manage so I went about creating a wrapper to make my life and everyone else’s a bit easier. I’m not going to explain how X Files are structured here, just briefly how to use my wrapper. This implementation only deals with loading data from a preexisting .x files and does not address saving data. The XFile object makes dealing with X files similar to using a stacks and lists. Data objects are pushed and popped and siblings of the current element are then iterated in order via next. X files do not allow reverse iteration so once a push, pop, or next action is executed there is no going back. Initially, the XFiles current data object is invalid (similar to an iterator pointing to end() ). To iterate through root frames use the NextRoot function, after the first call the XFile is set to the first root data object. The push operations leave the current data object invalid ( again similar to an iterator pointing to end() ). In order to access these child data objects the NextSibling function must be called, after a call to push, NextSibling moves to the first child data object. All other operations are performed on the current data object ( if valid ).

Below are some simple functions that iterate an X file using the XFile wrapper object.

bool Loader::Init(void *pvSource)
{
XFile *pTemp = new XFile;
       pTemp-Create(pvSource,

reinterpret_cast<const void*(g_pszPEXFileTemplates), strlen(g_pszPEXFileTemplates); m_pXFile = pTemp; }

void Loader::LoadToWorld(WorldTree *pWorldTree, WorldFrame *pRootFrame) { m_pWorldTree = pWorldTree;

if(NULL == pRootFrame) pRootFrame = pWorldTree-RootFrame();

// Loop through all the root frames in the file while(m_pXFile-NextRoot()) { LoadFrame(pRootFrame); } }

void Loader::LoadFrame(WorldFrame *pFrame) { // Load the data WorldFrame *pCurrentFrame = LoadData(pFrame);

// Move to the frame data if(m_pXFile-Push()) { // iterate through the children while(m_pXFile-NextSibling()) { LoadFrame(pCurrentFrame); } m_pXFile-Pop(); } }

WorldFrame* Loader::LoadData(WorldFrame *pFrame) { if(m_pXFile-IsCurrent(TID_D3DRMHeader)) { } else if(m_pXFile-IsCurrent(XFTID(Frame))) { // return the new child frame } else if(m_pXFile-IsCurrent(TID_D3DRMFrameTransformMatrix)) { // load some data, in this case the frame transform matrix D3DXMATRIX *pMatrix; m_pXFile-GetFloatArray("frameMatrix", reinterpret_cast <float*&(pMatrix)); pFrame-SetTransform(*pMatrix); } // else if… }



In order to compile the XFile object you will need to replace the two macros D3DEX and PEASSERT as I don’t provide the implementations. Also, the CD3DInterfacePtr will need to be replaced with some other auto COM pointer, the ATL COM pointer should work fine.

Currently browsing [XFile.zip] (4,226 bytes) - [XFile.h] - (4,078 bytes)

// XFile.h: interface for the XFile class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_XFILE_H__BF50AAEB_41CA_4AE1_A190_CD5B82531E93__INCLUDED_)
#define AFX_XFILE_H__BF50AAEB_41CA_4AE1_A190_CD5B82531E93__INCLUDED_

#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <D3d8.h> #include <Dxfile.h> #include <list>

// GUIDs not defined by the DirectX RM headers // {3d82ab43-62da-11cf-ab39-0020af71e433} DEFINE_GUID(TID_D3DRMHeader, 0x3d82ab43, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33);

// {<10DD46A3-775B-11cf-8F52-0040333594A3>} DEFINE_GUID(TID_D3DRMQuaternion, 0x10DD46A3, 0x775B, 0x11cf, 0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3);

// {<A3EB5D44-FC22-429D-9AFB-3221CB9719A6>} DEFINE_GUID(TID_D3DRMPatch, 0xA3EB5D44, 0xFC22, 0x429D, 0x9A, 0xFB, 0x32, 0x21, 0xCB, 0x97, 0x19, 0xA6);

// {<D02C95CC-EDBA-4305-9B5D-1820D7704BBF>} DEFINE_GUID(TID_D3DRMPatchMesh, 0xD02C95CC, 0xEDBA, 0x4305, 0x9B, 0x5D, 0x18, 0x20, 0xD7, 0x70, 0x4B, 0xBF);

// {<B8D65549-D7C9-4995-89CF-53A9A8B031E3>} DEFINE_GUID(TID_D3DRMVertexDuplicationIndices, 0xB8D65549, 0xD7C9, 0x4995, 0x89, 0xCF, 0x53, 0xA9, 0xA8, 0xB0, 0x31, 0xE3);

// {<3CF169CE-FF7C-44ab-93C0-F78F62D172E2>} DEFINE_GUID(TID_D3DRMXSkinMeshHeader, 0x3CF169CE, 0xFF7C, 0x44ab, 0x93, 0xC0, 0xF7, 0x8F, 0x62, 0xD1, 0x72, 0xE2);

// {<6F0D123B-BAD2-4167-A0D0-80224F25FABB>} DEFINE_GUID(TID_D3DRMSkinWeights, 0x6F0D123B, 0xBAD2, 0x4167, 0xA0, 0xD0, 0x80, 0x22, 0x4F, 0x25, 0xFA, 0xBB);

struct __declspec(uuid("3d82ab45-62da-11cf-ab39-0020af71e433")) IDirectXFileDataReference; struct __declspec(uuid("3d82ab44-62da-11cf-ab39-0020af71e433")) IDirectXFileData;

// You will need to replace these with some other auto COM ptr // the ATL one sould work typedef CD3DInterfacePtr<IDirectXFile> IDirectXFilePtr; typedef CD3DInterfacePtr<IDirectXFileEnumObject> IDirectXFileEnumObjectPtr; typedef CD3DInterfacePtr<IDirectXFileData> IDirectXFileDataPtr; typedef CD3DInterfacePtr<IDirectXFileObject> IDirectXFileObjectPtr; typedef CD3DInterfacePtr<IDirectXFileDataReference> IDirectXFileDataReferencePtr; typedef CD3DInterfacePtr<IDirectXFileBinary> IDirectXFileBinaryPtr;

class XFile { typedef std::list<IDirectXFileDataPtr> flie_data_stack;

IDirectXFilePtr m_pXFile; IDirectXFileEnumObjectPtr m_pEnumObject; IDirectXFileDataPtr m_pCurrentObject; flie_data_stack m_stackFileData; const GUID *m_pCurrentType;

public: struct coords2d { float u; float v; }; struct meshface { DWORD nFaceVertexIndices; DWORD pFaceVertexIndices[3]; };

XFile(); virtual ~XFile(); void Create(void *pvSource, const void *pvTemplate = NULL, DWORD dwTemplateSize = 0, DWORD dwLoadFlags = DXFILELOAD_FROMFILE, bool bLoadTemplatesFromFile = false, bool bUseStandardTemplates = true); // iteration bool Push(); bool Pop(); bool NextSibling(); bool NextRoot();

// identification bool IsCurrent(REFGUID refGuid); bool CurrentType(GUID &refGuid); bool CurrentID(GUID &refGuid); bool CurrentName(std::string &strName);

// data retrieval bool GetString(LPCSTR szName, char *&pszName); bool GetStringArray(LPCSTR szName, char **&ppszName); bool GetDword(LPCSTR szName, DWORD &dwData); bool GetDwordArray(LPCSTR szName, DWORD *&pDWArray); bool GetFloat(LPCSTR szName, float &fData); bool GetFloatArray(LPCSTR szName, float *&pFArray); bool GetVector3(LPCSTR szName, D3DVECTOR &vecVector3); bool GetVector3Array(LPCSTR szName, D3DVECTOR *&pVectors); bool GetColorRGBA(LPCSTR szName, D3DCOLORVALUE &rgbColorRGBA); bool GetFaceArray(LPCSTR szName, meshface *&pFaces); bool Get2DTextureCoordArray(LPCSTR szName, coords2d *&pCoords);

// utility IDirectXFileDataPtr& CurrentDataObject(void);

protected: bool GetChildDataObject(IDirectXFileDataPtr &pDataObject, const IDirectXFileDataPtr & pFileObject);

};

#endif //!defined(AFX_XFILE_H__BF50AAEB_41CA_4AE1_A190_CD5B82531E93__INCLUDED_)

Currently browsing [XFile.zip] (4,226 bytes) - [XFile.cpp] - (13,732 bytes)

// XFile.cpp: implementation of the XFile class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <rmxftmpl.h>
#include <initguid.h>
#include "..\INCLUDE\XFile.h"

#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif

// error macros I use, sorry no sorce 8p // replace with anything you like #define D3DEX(_h_result_) _h_result_ #define PEASSERT(_eval_)

////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// XFile::XFile() : m_pCurrentType(NULL) { }

XFile::~XFile() { }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::Create // Description : Initializes the XFile object and sets up iteration // Return type : void // Argument : void *pvSource :pointer to source file name or raw data // Argument : void *pvTemplate :pointer to template file name or data // Argument : DWORD dwTemplateSize :size of template data in bytes // Argument : DWORD dwLoadFlags :pvSource data type flag // Argument : bool bLoadTemplatesFromFile :pvTemplate data type flag // void XFile::Create(void *pvSource, const void *pvTemplate /*= NULL*/, DWORD dwTemplateSize /*= 0*/, DWORD dwLoadFlags /*= DXFILELOAD_FROMFILE*/, bool bLoadTemplatesFromFile /*= false*/, bool bUseStandardTemplates /*= true*/) { IDirectXFilePtr pXFile; IDirectXFileEnumObjectPtr pEnumObject;

// Create the XFile object interface D3DEX(DirectXFileCreate(&pXFile.Interface()));

// Register the standard templates if(bUseStandardTemplates) D3DEX(pXFile->RegisterTemplates((VOID*)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES));

// If there are custom templates try to load them if(NULL != pvTemplate) { if(bLoadTemplatesFromFile) { // Not supported yet, pvTemplate should be file name, path, stream or something PEASSERT(bLoadTemplatesFromFile == true); } else { D3DEX(pXFile->RegisterTemplates(const_cast<void*>(pvTemplate), dwTemplateSize)); } }

// Now create the enum object D3DEX(pXFile->CreateEnumObject(pvSource, dwLoadFlags, &pEnumObject.Interface())) m_pXFile = pXFile; m_pEnumObject = pEnumObject; }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::Push // Description : Moves iteration to children of current opbjec // Return type : bool // bool XFile::Push() { bool bRet = false;

if(m_pCurrentObject) { m_stackFileData.push_back(m_pCurrentObject); m_pCurrentType = NULL; m_pCurrentObject = NULL; bRet = true; }

return bRet; }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::Pop // Description : Moves iteration to parent of current object // Return type : bool // bool XFile::Pop() { bool bRet = false; if(!m_stackFileData.empty()) { m_pCurrentObject = m_stackFileData.back(); m_stackFileData.pop_back(); D3DEX(m_pCurrentObject->GetType(&m_pCurrentType)); bRet = true; }

return bRet; }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::NextSibling // Description : Moves iteration to next sibling object // Return type : bool // bool XFile::NextSibling() { bool bRet = false;

if(!m_stackFileData.empty()) { IDirectXFileDataPtr pChild;

if(GetChildDataObject(pChild, m_stackFileData.back())) { m_pCurrentObject = pChild; D3DEX(m_pCurrentObject->GetType(&m_pCurrentType)); bRet = true; } } return bRet; }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::NextRoot // Description : Moves iteration to next root object // Return type : bool // bool XFile::NextRoot() { IDirectXFileDataPtr pRoot; HRESULT hr;

m_stackFileData.clear(); m_pCurrentObject = NULL; m_pCurrentType = NULL;

if(SUCCEEDED(hr = m_pEnumObject->GetNextDataObject(&pRoot.Interface()))) { if(FAILED(hr = pRoot.QueryInterface(m_pCurrentObject))) { IDirectXFileDataReferencePtr pReference; if(SUCCEEDED(hr = pRoot.QueryInterface(pReference))) { D3DEX(pReference->Resolve(&m_pCurrentObject.Interface())); pReference = NULL; } }

}

if(SUCCEEDED(hr)) { m_pCurrentObject->GetType(&m_pCurrentType); } return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::IsCurrent // Description : Compares type of current object // Return type : bool // Argument : REFGUID rGuid // bool XFile::IsCurrent(REFGUID rGuid) { PEASSERT(m_pCurrentType); return NULL != m_pCurrentType && IsEqualGUID(rGuid, *m_pCurrentType); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::CurrentType // Description : Gets the current objects GUID // Return type : bool // Argument : GUID & refGuid // bool XFile::CurrentType(GUID & refGuid) { if(m_pCurrentType) refGuid = *m_pCurrentType;

return NULL != m_pCurrentType; }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::CurrentID // Description : Gets the current objects ID // Return type : bool // Argument : GUID &refGuid // bool XFile::CurrentID(GUID &refGuid) { if(!m_pCurrentObject) D3DEX(m_pCurrentObject->GetId(&refGuid));

return !m_stackFileData.empty(); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::CurrentName // Description : Gets the current objects name // Return type : bool // Argument : std::string &strName // bool XFile::CurrentName(std::string &strName) { DWORD dwLen; if(m_pCurrentObject) { m_pCurrentObject->GetName(NULL, &dwLen); strName.resize(dwLen); D3DEX(m_pCurrentObject->GetName(&strName[0], &dwLen)); } return 0 != strName.size(); }

IDirectXFileDataPtr& XFile::CurrentDataObject(void) { return m_pCurrentObject; }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetString // Description : Gets a string value // Return type : bool // Argument : LPCSTR szName // Argument : char *&pszName // bool XFile::GetString(LPCSTR szName, char *&pszName) { DWORD dwSize = 0; char **ppString; HRESULT hr;

if(SUCCEEDED( hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&ppString))) ) pszName = *ppString;

PEASSERT(SUCCEEDED(hr)); return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetStringArray // Description : Gets an array of string values // Return type : bool // Argument : LPCSTR szName // Argument : char **&ppszName // bool XFile::GetStringArray(LPCSTR szName, char **&ppszName) { DWORD dwSize = 0; char **ppString; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&ppString)); ppszName = ppString; PEASSERT(SUCCEEDED(hr)); return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetDword // Description : Gets a DWORD value // Return type : bool // Argument : LPCSTR szName // Argument : DWORD &dwData // bool XFile::GetDword(LPCSTR szName, DWORD &dwData) { DWORD *pDWORD; DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pDWORD)); if(SUCCEEDED(hr) && sizeof(DWORD) == dwSize) dwData = *pDWORD; else PEASSERT(SUCCEEDED(hr) && sizeof(DWORD) == dwSize);

return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetDwordArray // Description : Gets an array of DWORD values // Return type : bool // Argument : LPCSTR szName // Argument : DWORD *&pDWArray // bool XFile::GetDwordArray(LPCSTR szName, DWORD *&pDWArray) { DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pDWArray)); PEASSERT(SUCCEEDED(hr) && 0 == dwSize % sizeof(DWORD)); return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetFloat // Description : Gets a float value // Return type : bool // Argument : LPCSTR szName // Argument : float &fData // bool XFile::GetFloat(LPCSTR szName, float &fData) { float *pFloat; DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pFloat)); if(SUCCEEDED(hr) && sizeof(float) == dwSize) fData = *pFloat; else PEASSERT(SUCCEEDED(hr) && sizeof(float) == dwSize);

return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetFloatArray // Description : Gets an array of float values // Return type : bool // Argument : LPCSTR szName // Argument : float *&pFArray // bool XFile::GetFloatArray(LPCSTR szName, float *&pFArray) { DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pFArray)); PEASSERT(SUCCEEDED(hr) && 0 == dwSize % sizeof(float)); return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetVector3 // Description : Gets a 3 component vector // Return type : bool // Argument : LPCSTR szName // Argument : D3DVECTOR &vecVector // bool XFile::GetVector3(LPCSTR szName, D3DVECTOR &vecVector) { D3DVECTOR *pVec; DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pVec)); PEASSERT(SUCCEEDED(hr) && dwSize == sizeof(D3DVECTOR)); vecVector = *pVec; return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetVector3Array // Description : Gets an array of 3 component vectors // Return type : bool // Argument : LPCSTR szName // Argument : D3DVECTOR *&pVectors // bool XFile::GetVector3Array(LPCSTR szName, D3DVECTOR *&pVectors) { DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pVectors)); PEASSERT(SUCCEEDED(hr) && 0 == dwSize % sizeof(D3DVECTOR)); return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetColorRGBA // Description : Gets an RGBA color value // Return type : bool // Argument : LPCSTR szName // Argument : D3DCOLORVALUE &rgbColorRGBA // bool XFile::GetColorRGBA(LPCSTR szName, D3DCOLORVALUE &rgbColorRGBA) { D3DCOLORVALUE *pColor; DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pColor)); PEASSERT(SUCCEEDED(hr) && dwSize == sizeof(D3DCOLORVALUE)); rgbColorRGBA = *pColor; return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetFaceArray // Description : Gets an array of faces // Return type : bool // Argument : LPCSTR szName // Argument : meshface *&pFaces // bool XFile::GetFaceArray(LPCSTR szName, meshface *&pFaces) { DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pFaces)); PEASSERT(SUCCEEDED(hr) && 0 == dwSize % sizeof(meshface)); return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::Get2DTextureCoordArray // Description : Gets an array of 2D texture coords // Return type : bool // Argument : LPCSTR szName // Argument : coords2d *&pCoords // bool XFile::Get2DTextureCoordArray(LPCSTR szName, coords2d *&pCoords) { DWORD dwSize; HRESULT hr = m_pCurrentObject->GetData(szName, &dwSize, reinterpret_cast<void**>(&pCoords)); PEASSERT(SUCCEEDED(hr) && 0 == dwSize % sizeof(coords2d)); return SUCCEEDED(hr); }

/////////////////////////////////////////////////////////////////////////////// // Function name : XFile::GetChildDataObject // Description : Gets the next child data object // Return type : bool // Argument : IDirectXFileDataPtr &pDataObject // Argument : const IDirectXFileDataPtr & pFileObject // bool XFile::GetChildDataObject(IDirectXFileDataPtr &pDataObject, const IDirectXFileDataPtr & pFileObject) { HRESULT hr; IDirectXFileObjectPtr pChildObject;

if(SUCCEEDED(hr = pFileObject->GetNextObject(&pChildObject.Interface()))) { if(FAILED(hr = pChildObject.QueryInterface(pDataObject))) { IDirectXFileDataReferencePtr pReference; if(SUCCEEDED(hr = pChildObject.QueryInterface(pReference))) { D3DEX(pReference->Resolve(&pDataObject.Interface())); pReference = NULL; } else PEASSERT(false); } } return SUCCEEDED(hr); }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.