Jump to content
  • Advertisement
Sign in to follow this  
cNoob

My model format

This topic is 4326 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

Hey, I've decided I want to create my own model model format just for practice. I wont be creating complex models with my format just very simple box rooms. However this is my first attempt at creating my own file format. Heres what my model file looks like for a square:
#TRIANGLES 2
#BEGIN
-0.1 0.0 0.0 -0.1 0.1 0.0 0.1 0.0 0.0
0.1 0.1 0.0 -0.1 0.1 0.0 0.1 0.0 0.0
#END


For now im just trying to load the format not put it into a mesh struct just yet. So heres what I've got so far:
////////////////////////////////////////////////////////////////////////////////
// MatsModelFormat Loader
// Matthew Henley
// 15/10/2006
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>

void LoadModel(std::string filename);

////////////////////////////////////////////////////////////////////////////////
// main()
////////////////////////////////////////////////////////////////////////////////
int main()
{
        LoadModel("Square.mmf");
        system("pause");
}

////////////////////////////////////////////////////////////////////////////////
// LoadModel()
////////////////////////////////////////////////////////////////////////////////
void LoadModel(std::string filename)
{
        std::string command;
        int triangles;
        
        std::ifstream model(filename.c_str());

            model >> command;
            if(command == "#TRIANGLES")
               model >> triangles;
        
        model.close();
        
        std::cout << "There Are " << triangles << " Triangles In The Model " << filename.c_str() << "\n";
}


At the moment I am able to see how many triangles there are in my model. Am I going the right way about creating my LoadModel function or am I completely of track.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by cNoob
...or am I completely of track.
Nope - that's a good start :)

Two quick notes. In general, constant references should be preferred for arguments with non-trivial types:
void LoadModel(const std::string& filename)
Also, it's good to get into the habit of using braces consistently. It's tempting to leave them out for single-line blocks of code, but it's error-prone and can make the code more difficult to follow:
if (command == "#TRIANGLES") {
model >> triangles;
}
One of the things you're doing here is writing a parser. Depending on its intended purpose a parser can be quite complex, but even a simple parser should be aware of (and handle gracefully) unexpected or invalid input.

In the context of your current code, you could start by asking a few basic questions. What happens if there is no token after the '#TRIANGLES' token? What if there is, but it's not a valid integer value? What if there's an unrecognized token?

Once you've gotten a little farther, you might consider offloading some of the work to, say, boost::tokenizer and boost::lexical_cast(). This will simplify your code and cut down on development time. There are also many complete solutions available, such as boost::spirit and various free XML parsers, that you might consider in the future.

Share this post


Link to post
Share on other sites
I'd recommend that you separate vertexes from triangles, and use vertex indexes in the triangles, rather than explicit vertex positions.

That said, it would probably benefit you more overall to do something like building an XML-based format, and learning how to use XML libraries to read structured files.

Share this post


Link to post
Share on other sites
OK thanks for the reply's guys,

jyk, I have fixed all my code blocks thanks for that warning.

I decided at the start I only wanted a very simple format and by having tokens(#TRIANGLES & #BEGIN & #END) it was making my loading alot more complex so I have taken them out and heres a typical model in "Mats Model Format" :)

Pyramid.mmf

4
-0.5 0.0 -0.5 33333 0.0 1.0 0.0 99999 0.5 0.0 -0.5 33333
0.5 0.0 -0.5 33333 0.0 1.0 0.0 99999 0.5 0.0 0.5 33333
0.5 0.0 0.5 33333 0.0 1.0 0.0 99999 -0.5 0.0 0.5 33333
-0.5 0.0 0.5 33333 0.0 1.0 0.0 99999 -0.5 0.0 -0.5 33333





The first number is how many triangles in the mesh there is, Then we have the x,y,z positions and a value for colour for each vertex.

A quick demo I just put together to load the Pyramid.mmf file and render it whilst rotating on the y-axis. Feel free to compile :P


#include <windows.h>
#include <iostream>
#include <fstream>
#include <d3d9.h>
#include <d3dx9.h>

void Initialize(HWND &hWnd);
void Render();
void CleanUp();

IDirect3D9* g_pD3D = NULL;
IDirect3DDevice9* g_pD3DDevice = NULL;

class MMF
{
private:
int m_iTriangles;
int m_iVertices;
IDirect3DVertexBuffer9* m_pVertexBuffer;

struct mmf_vertex
{
float x,y,z;
DWORD colour;
};
#define MMF_VERTEX_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)

public:
MMF();
~MMF();

void LoadModel(const std::string& filename, IDirect3DDevice9* &device);
void Render(IDirect3DDevice9* &device);

protected:
void CleanUp();
};

MMF::MMF()
{
m_iTriangles = 0;
m_iVertices = 0;
m_pVertexBuffer = NULL;
}

MMF::~MMF()
{
CleanUp();
}

void MMF::LoadModel(const std::string& filename, IDirect3DDevice9* &device)
{
std::ifstream mmf(filename.c_str());

mmf >> m_iTriangles;
m_iVertices = m_iTriangles*3;
mmf_vertex vertices[m_iVertices];

for(int i=0; i<m_iVertices; i++)
{
mmf >> vertices.x;
mmf >> vertices.y;
mmf >> vertices.z;
mmf >> vertices.colour;
}

mmf.close();

CleanUp();

device->CreateVertexBuffer(sizeof(vertices), 0,
MMF_VERTEX_FVF, D3DPOOL_MANAGED, &m_pVertexBuffer, NULL);

void* pData;
m_pVertexBuffer->Lock(0, sizeof(pData), (void**)&pData, 0);
memcpy(pData, vertices, sizeof(vertices));
m_pVertexBuffer->Unlock();
}

void MMF::Render(IDirect3DDevice9* &device)
{
device->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(mmf_vertex));
device->SetFVF(MMF_VERTEX_FVF);
device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, m_iTriangles);
}

void MMF::CleanUp()
{
if(m_pVertexBuffer != NULL){
m_pVertexBuffer->Release();
}
}

MMF mmfPyramid;

LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
}break;

case WM_KEYDOWN:
{
switch(wParam)
{
case VK_ESCAPE:
{
PostQuitMessage(0);
}break;
}
}break;

default:break;
}
return(DefWindowProc(hWnd, msg, wParam, lParam));
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
WNDCLASSEX winclass;
HWND hWnd;
MSG msg;

winclass.cbSize = sizeof(WNDCLASSEX);
winclass.cbWndExtra = 0;
winclass.cbClsExtra = 0;
winclass.style = 0;
winclass.hInstance = hInstance;
winclass.lpfnWndProc = WinProc;
winclass.lpszClassName = "MMFLOADER";
winclass.lpszMenuName = NULL;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

RegisterClassEx(&winclass);

hWnd = CreateWindowEx(NULL,
"MMFLOADER",
"Mats Model Format Loader",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
640, 480,
NULL,
NULL,
hInstance,
NULL);

Initialize(hWnd);

while(1)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT){
break;
}

TranslateMessage(&msg);
DispatchMessage(&msg);
}
Render();
}
CleanUp();
return(msg.wParam);
}

void Initialize(HWND &hwnd)
{
g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = true;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferWidth = 800;
d3dpp.BackBufferHeight = 600;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;

g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice);

g_pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, false);

mmfPyramid.LoadModel("Pyramid.mmf", g_pD3DDevice);
}

void Render()
{
g_pD3DDevice->Clear(0,0,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),0,0);
g_pD3DDevice->BeginScene();

D3DXMATRIX matWorld, matView, matProj;
D3DXMatrixRotationY(&matWorld, timeGetTime()/1000.0f);
g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(0.0f, 3.0f, -3.0f),
&D3DXVECTOR3(0.0f, 0.5f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
g_pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);

mmfPyramid.Render(g_pD3DDevice);

g_pD3DDevice->EndScene();
g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}

void CleanUp()
{
if(g_pD3DDevice != NULL){
g_pD3DDevice->Release();
}

if(g_pD3D != NULL){
g_pD3D->Release();
}
}



Heres a quick screenshot:


So for a nights work I think I have done ok, I'm hoping to get simple textures splatted onto the mesh so for that im guessing im going to need the filepath of the image and texture co-ordinates for each vertex, right?

If there is anything wrong or and bad design with what I have got so far do'nt hesitate to tell me. Thanks.

Share this post


Link to post
Share on other sites
hmmm, I suggest that you take a look at 3DMax's ascii export, and after you remove all it' gibberish crap, I think you will notice strange resembelance with you own format.
IMO you should write parser of MAX's and try to load it in scene.
Not to mention that it could enable you to export complex models and import it in your scene by not using any of the standards.
Alternatly you could write your own MAX ascii export based on MAX's original but with your own keywords, like: #TRIANGLES 2 #BEGIN...
It could really save you lots of time, and teach you at the same time.

Share this post


Link to post
Share on other sites
I think I'd loose brain cells trying to fix a problem loading a model like this:

-0.1 0.0 0.0 -0.1 0.1 0.0 0.1 0.0 0.0
0.1 0.1 0.0 -0.1 0.1 5.0 0.1 1.0 0.0
-0.1 0.0 3.4 -0.1 0.1 0.0 0.1 0.0 0.0
0.1 0.1 3.7 -0.1 0.1 0.1 0.1 2.0 0.0
-0.1 0.0 0.0 -0.1 0.1 0.0 0.1 0.0 0.0
0.1 0.1 0.0 -0.1 0.1 0.0 0.1 0.0 0.0

Just trying to mentally seperate the numbers is nearly impossible (those spaces and dots all run together).

But cool none-the-less. Good luck to you.

When I started learning OpenGL I did the same thing, only in xml, like:


<model>
<triangle_strip>
<vertex x="1.0" y="0.0" z="1.0" />
<vertex x="1.0" y="1.0" z="1.0" />
<vertex x="0.0" y="0.0" z="1.0" />
<vertex x="2.0" y="0.0" z="1.0" />
<vertex x="2.0" y="1.0" z="1.0" />
</triangle_strip>
</model>



Of course as I added more support for features, my file format design changes too (not just new keywords, but reorganization to better model the idea of my OpenGL understanding). I still don't have a very good format, but at least I can hand create simple 2D vector graphics and composite them into larger models, works for my current simple needs - although I'm really wishing I knew how to make use of stuff like trueSpace models".

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!