how to load an X file

Started by
10 comments, last by synth_cat 17 years, 10 months ago
Maybe this is not even possible, but here's what I want to do: I want to be able to load triangle xyz data from an X file float by float. I don't want to use a DX function to do this, because I'm not planning on using X-file-loading to fill my game's vertex buffer or a DirectX mesh or anything like that. I want to be able to load X files into my world modeler, filling my own struct MyTriangle array with xyz data. To explain briefly why I would want to do something so strange: The files that my worldmaker generates read as follows: int number_of_tris, block of triangle data (xyz, uv, etc.), physics geometry and other stuff.) Recently I have been using my own modelling tools to create geometry within my world editor, but they are so hard to write and hard to use that I would like to do the geometry-creation in a professional modeller and then just use my worldmaker for texturing, creation of physics geometry, and other stuff. Is this even possible? Is it legal? If so, what is the structure of an X file and where can I find out (I had trouble finding this kind of info on msdn.com)? Remember that all I care about is the straight position data. (I will be making these X files with Caligari TrueSpace6.6, if that means anything.) By the way, what is the effective difference between an ASCII X file and a ibnary X file? Thanks!
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Advertisement
What you can do is simply load the file into the standard DirectX mesh format and, using a class in somewhere in the SDK (it's called crackdecl.h/crackdecl.cpp and it's in the \Samples\C++\Direct3D\UVAtlas directory) you can extract info about the vertex declaration. Then it's as simple as locking the vertex buffer and stepping through the data. Shouldn't be too hard. I can at least start you off:
ID3DXMesh* mesh;HRESULT hr = D3DXLoadMeshFromX("your_mesh.x", D3DXMESH_SYSTEMMEM, g_d3dDevice, NULL, NULL, NULL, NULL, &mesh);if(FAILED(hr))   //scream and run awayvoid* vertBuffer;mesh->LockVertexBuffer(D3DLOCK_READONLY, &vertBuffer);//do stuff with vertex buffermesh->UnlockVertexBuffer();


And you can also do that with the index buffer so you can reassemble the faces properly. Hope that at least gets you going.
ASCII and Binary are just different representations of the same data. ASCII can be a read and edited by us humans, binary can't (unless you're some sort of super-hardcore nerd who can read binary [lol]). In practice the difference is usually that binary encoding generates a much smaller file.

I'd also second NickGravelyn's approach. Why make your job any harder by writing your own parser?

Although, I might add a few things:

1. Use ID3DXMesh::CloneMeshFVF() with the D3DFVF_XYZ flag - this will strip out any unwanted vertex attributes. Might be safest to check that component actually exists first of course [wink]

2. Use GetNumFaces() and iterate through the index buffer, each triple of indices defines one face. Store these for the next step.

3. Lock the vertex buffer and for each triple of indices you just looked up, extract the relevant vertex from the buffer. Because of step #1 your returned pointer is just an array of D3DXVECTOR3's so its easy to just copy the XYZ position to your new structure.

Once all thats done, release the mesh and any temporary data.

Or, if you really wanna do it the hard way you'll need to get familiar with the .X file format reference section in the SDK documentation.

hth
Jack

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

Take a look at this article: Loading and displaying .X files without DirectX, maybe it can help.
Thanks for the reference to that article, but I'm not sure if it will help me much, seeing as I am only going to be loading non-animated stuff.

I have a question about the function D3DXLoadMeshFromX(): Is this function "smart?" In other words, will it be able to handle any sort of .x file I throw at it? It's just that I'm not sure what sort of .x my modeller will generate.

Otherwise this seems like a really good way to go - _much_ better than a parser, especially now that I see how complicated the .x file actually is.

Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Quote:Original post by synth_cat
I have a question about the function D3DXLoadMeshFromX(): Is this function "smart?" In other words, will it be able to handle any sort of .x file I throw at it? It's just that I'm not sure what sort of .x my modeller will generate.
It should be fine - I've never had any problems with it myself, nor am I aware of other people have problems.

The .x format is extensible so you might not get ALL the information in a file (I'd expect D3DXLoadMeshFromX() to drop any data that an ID3DXMesh container can't represent). Given you only want vertex/position data you shouldn't have a problem here [smile]

hth
Jack

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

Just out of curiosity, how would I go about creating a .x file?
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Quote:Original post by synth_cat
Just out of curiosity, how would I go about creating a .x file?
You could do it procedurally in code by using D3DXCreateMesh() or you could use your favourite modelling package. Both Wings3D and Blender are free downloads - things like Max and Maya are more popular but might require you to sell bodyparts for medical research in order to pay [lol]

For questions regarding the modelling process (and packages) you might wanna swing by the Visual Arts forum.

hth
Jack

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

Sorry for not answering for so long -

Anyway, I tried out the method (for loading data from an X file into my own TRI and POINT structs), and it didn't exactly work. Let me explain: I'll start off with showing you the code:
//structsstruct TRI{     bool alive;     int pnt_idx1;     int pnt_idx2;     int pnt_idx3;};struct POINT{     float x;     float y;     float z;};//these two arrays are the heart of my modeller and need to be filled with//data from the x fileTRI tris[MAX_TRIS];POINT pnts[MAX_PNTS];//here is the function that is meant to load data from an X filevoid InitWorldFromX(){        //by doing this, I set all the .alive members of tris to 0,        //so I can check later on how many tris were actually loaded into        //tris[] from the file        ZeroMemory(&tris,sizeof(tris));        ZeroMemory(&pnts,sizeof(pnts));	ID3DXMesh* mesh;	HRESULT test;          test=D3DXLoadMeshFromX("testfile.x",D3DXMESH_SYSTEMMEM,d3ddev,                               0,0,0,0,&mesh);	if(FAILED(test))	{ return; //didn't work }	//now clone this mesh to a mesh with correct FVF	ID3DXMesh* clone_mesh;	mesh->CloneMeshFVF(mesh->GetOptions(),D3DFVF_XYZ,d3ddev,&clone_mesh); 	num_tris=clone_mesh->GetNumFaces();	num_verts=clone_mesh->GetNumVertices();	if(num_tris>=TRIS_SIZE) return;	if(num_verts>=POINTS_SIZE) return;        /////////////////////////////////////////////////////////////////        ////////////////GET XYZ DATA FROM MESH'S VERTEX BUFFER////////        /////////////////////////////////////////////////////////////////	POINT* meshvb_pnt=0;	mesh->LockVertexBuffer(D3DLOCK_READONLY,(void**)&meshvb_pnt);	if(!meshvb_pnt) return; //failed	for(int read_pnt=0; read_pnt<num_verts; read_pnt++)	{		pnts[read_pnt].p.x=meshvb_pnt[read_pnt].x;		pnts[read_pnt].p.y=meshvb_pnt[read_pnt].y;		pnts[read_pnt].p.z=meshvb_pnt[read_pnt].z;	}	mesh->UnlockVertexBuffer();        /////////////////////////////////////////////////////////////////        ////////////////FILL TRI INDECES FROM MESH'S INDEX BUFFER////////        /////////////////////////////////////////////////////////////////	WORD* meshib_pnt=0;	mesh->LockIndexBuffer(D3DLOCK_READONLY,(void**)&meshib_pnt);	if(!meshib_pnt) return; //failed	for(int read_tri=0; read_tri<num_tris; read_tri++)	{		tris[read_tri].alive=1;		tris[read_tri].p[0]=(int)meshib_pnt[read_tri*3];		tris[read_tri].p[1]=(int)meshib_pnt[read_tri*3+1];		tris[read_tri].p[2]=(int)meshib_pnt[read_tri*3+2];	}	mesh->UnlockVertexBuffer();        //release the two mesh pointers	clone_mesh->Release();	mesh->Release();	return;};


Anyway, here's the problem: When I call InitWorldFromX(), I get nothing on my screen (when tris[] and pnts[] are sent to my drawing functions, I mean.) Now I _do_ know that creating the meshes has worked because I can look through my tris[] array and check .alive values and tell that 392 tris have been filled in.

So, does anyone know what exactly the problem is? I feel sure it has something to do about the way I load xyz data from the file...
	POINT* meshvb_pnt=0;	mesh->LockVertexBuffer(D3DLOCK_READONLY,(void**)&meshvb_pnt);	if(!meshvb_pnt) return; //failed	for(int read_pnt=0; read_pnt<num_verts; read_pnt++)	{		pnts[read_pnt].p.x=meshvb_pnt[read_pnt].x;		pnts[read_pnt].p.y=meshvb_pnt[read_pnt].y;		pnts[read_pnt].p.z=meshvb_pnt[read_pnt].z;	}	mesh->UnlockVertexBuffer();

...or with the way I load index data.
	WORD* meshib_pnt=0;	mesh->LockIndexBuffer(D3DLOCK_READONLY,(void**)&meshib_pnt);	if(!meshib_pnt) return; //failed	for(int read_tri=0; read_tri<num_tris; read_tri++)	{		tris[read_tri].alive=1;		tris[read_tri].p[0]=(int)meshib_pnt[read_tri*3];		tris[read_tri].p[1]=(int)meshib_pnt[read_tri*3+1];		tris[read_tri].p[2]=(int)meshib_pnt[read_tri*3+2];	}	mesh->UnlockVertexBuffer();


My thanks in advance!
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Oops, my mistake! I just realized that the code in my project was this:
        WORD* meshib_pnt=0;	mesh->LockIndexBuffer(D3DLOCK_READONLY,(void**)&meshib_pnt);	if(!meshib_pnt) return; //failed	for(int read_tri=0; read_tri<num_tris; read_tri++)	{		tris[read_tri].alive=1;		tris[read_tri].p[0]=(int)meshib_pnt[read_tri*3];		tris[read_tri].p[0]=(int)meshib_pnt[read_tri*3+1];		tris[read_tri].p[0]=(int)meshib_pnt[read_tri*3+2];	}	mesh->UnlockVertexBuffer();     

So obviously I wouldn't have seen anything because only index 0 of each triangle got defined. I fixed this and my geometry appeared!

However, I still want to ask everyone out there if I'm going about this the correct way. Is my crude method of using a POINT* pointer to unlock the vertex buffer the safest thing to do? Will it fail on some .x files, possibly?
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith

This topic is closed to new replies.

Advertisement