Quake3World.com Forums
     Programming Discussion
        MD3 model loader in C++


Post new topicReply to topic
Login | Profile | | FAQ | Search | IRC




Print view Previous topic | Next topic 
Topic Starter Topic: MD3 model loader in C++

Recruit
Recruit
Joined: 11 Jan 2010
Posts: 5
PostPosted: 01-11-2010 03:56 AM           Profile   Send private message  E-mail  Edit post Reply with quote


I'm trying to create a model loader for md3 files using C++. I have some tutorials and source code for some md2 model loaders. I also have the file format of md3 files from Wiki.

I'd like to have my models animated and with textures but at the moment I'm just having problems loading the model at all.

Any help would be appreciated. :)




Top
                 

Mentor
Mentor
Joined: 12 Mar 2005
Posts: 3958
PostPosted: 01-11-2010 05:05 AM           Profile Send private message  E-mail  Edit post Reply with quote


That's rather broad. Do you have specific issues you are running into?




Top
                 

Recruit
Recruit
Joined: 11 Jan 2010
Posts: 5
PostPosted: 01-12-2010 05:33 PM           Profile   Send private message  E-mail  Edit post Reply with quote


I'm currently having issues with understanding the code to get my loader to get read the information from the md3 file. I really don't know where to begin. I found some pages about md2 but it all looks so complicated and is really daunting.




Top
                 

Mentor
Mentor
Joined: 12 Mar 2005
Posts: 3958
PostPosted: 01-13-2010 01:23 AM           Profile Send private message  E-mail  Edit post Reply with quote


That's still not much to go on. =)

CS 101: break up the problem in smaller problems. Repeat until you can't break it up further. Think about how to approach each problem. Think some more. Start coding.




Top
                 

god xor reason
god xor reason
Joined: 08 Dec 1999
Posts: 21100
PostPosted: 01-19-2010 09:48 AM           Profile   Send private message  E-mail  Edit post Reply with quote


If something isn't working right, the most likely problem is you're not parsing the data properly. Being wrong by even 1-bit can have catastrophic consequences when you're talking about parsing thousands of array elements from a binary file. Focus on just loading the model data, and outputting it to the console before you worry about rendering (an application of what misantropia said). Try working with a simple model that you know for a fact has X number of verts/faces/tags etc. Once you get the counts perfect, move on to rendering.

Here is a solid guide to the format:
http://icculus.org/~phaethon/q3a/formats/md3format.html

If you really get stumped, take a peak at the q3 engine source.




Top
                 

Recruit
Recruit
Joined: 11 Jan 2010
Posts: 5
PostPosted: 02-01-2010 06:59 AM           Profile   Send private message  E-mail  Edit post Reply with quote


So, I've been trying to get something to work and I have managed to get all the data to read out properly (in text format) with the exception of multiple surfaces but I'm going to address that issue later as I'm just using a single surface model at the moment.

I also managed to get some triangles appear in the applet window, nothing like the model but it was something. While I was attempting to get it to produce the actual model I appear to have broken it. :( Now my applet just crashes without outputting any text or anything.

My Main.cpp was given to me by my lecturer and only defines the way that the model is drawn (colour, rotation etc). My GameObject.h is as follows:

Code:

#include <GL/gl.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <fstream>

using namespace std;

#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_

class GameObject
{
public:
   GameObject();
   GameObject(const char * filename);
   virtual ~GameObject();

   virtual void draw();

private:

   struct md3_header
   {
      int ident;
      int version;

      char name[64];

      int flags;
      int num_frames;
      int num_tags;
      int num_surfaces;
      int num_skins;

      int ofs_frames;
      int ofs_tags;
      int ofs_surfaces;
      int ofs_eof;
   };

   typedef float vec3[3];

   struct md3_frame_header
   {
      vec3 min_bounds;
      vec3 max_bounds;
      vec3 local_origin;
      float radius;
      char name[16];
   };

   struct md3_tag_header
   {
      char name[64];
      vec3 origin;
      vec3 axis[3];
   };

   struct md3_surface_header
   {
      int ident;
      char name[64];

      int flags;
      int num_frames;
      int num_shaders;
      int num_verts;
      int num_triangles;

      int ofs_triangles;
      int ofs_shaders;
      int ofs_st;
      int ofs_xyznormal;
      int ofs_end;
   };

   struct md3_shader_header
   {
      char name[64];
      int shader_index;
   };

   struct md3_triangle_header
   {
      int indexes[3];
   };

   struct md3_texcoord_header
   {
      float st[2];
   };

   struct md3_vertex_header
   {
      short coord[3];
      char normal[2];
   };
   vec3 * vertices;

      int num_frames;
      md3_frame_header * frames;
      int num_vertices;
      md3_vertex_header * verts;
      int num_surfaces;
      md3_surface_header * surfaces;
      int num_triangles;
      md3_triangle_header * triangles;
      int num_tags;
      md3_tag_header * tags;
      int num_shaders;
      md3_shader_header * shaders;
      md3_texcoord_header * coords;
};

#endif


My GameObject.cpp is:

Code:

#include "GameObject.h"

GameObject::GameObject()
{
}

GameObject::GameObject(const char * filename) {
   ifstream md3file;
   md3file.open(filename, ios::in|ios::binary);

   //C Stuff
   md3_header * md3header = (struct md3_header*)
         malloc(sizeof(struct md3_header));

   md3file.read((char *) md3header, sizeof (struct md3_header));

   if ((md3header->ident != 860898377) || (md3header->version <15)) {
   //Error!
      cerr << "Error: bad version or identifier" << endl;
}

   this->triangles = (md3_triangle_header *)
            calloc(this->surfaces->num_triangles,sizeof(struct md3_surface_header));
         md3file.seekg(this->surfaces->ofs_triangles, ios::beg);
         md3file.read((char*)triangles,sizeof (struct md3_triangle_header)* surfaces->num_triangles);

   this->surfaces= (md3_surface_header *)
         calloc(md3header->num_surfaces,sizeof(struct md3_surface_header));
   md3file.seekg(md3header->ofs_surfaces,ios::beg);
   md3file.read((char *) this->surfaces, sizeof(struct md3_surface_header));


   this->verts = (md3_vertex_header *)
      calloc(this->surfaces->num_verts,sizeof(struct md3_vertex_header));
   md3file.seekg(surfaces->ofs_xyznormal, ios::beg);
   md3file.read((char*)verts,sizeof (struct md3_vertex_header)* surfaces->num_verts);

   this->surfaces = (struct md3_surface_header *)
         calloc (md3header->ofs_surfaces, sizeof(struct md3_surface_header));
   md3file.seekg(md3header->ofs_surfaces,ios::beg);
   md3file.read((char*)surfaces, sizeof (struct md3_surface_header)* md3header->num_surfaces);


   this->frames = (struct md3_frame_header *)
         calloc (md3header->num_frames, sizeof(struct md3_frame_header));
   md3file.seekg(md3header->ofs_frames, ios::beg);
   md3file.read((char *) frames, sizeof (struct md3_frame_header) * md3header->num_frames);

   this->tags = (struct md3_tag_header *)
         malloc (sizeof(struct md3_tag_header) * md3header->num_tags);
   md3file.seekg(md3header->ofs_tags,ios::beg);
   md3file.read((char*)tags,sizeof(struct md3_tag_header)* md3header->num_tags);


         cout << "Ident: " << md3header->ident <<endl;
         cout << "Version: " << md3header->version <<endl;
         cout << "Name: " << md3header->name <<endl;
         cout << "Flags: " << md3header->flags <<endl;
         cout << "Num Frames: " << md3header->num_frames <<endl;
         cout << "Num_tags: " << md3header->num_tags <<endl;
         cout << "Num Surfaces: " << md3header->num_surfaces <<endl;
         cout << "Num Skins: " << md3header->num_skins <<endl;
         cout << "Ofs Frames: " << md3header->ofs_frames <<endl;
         cout << "Ofs Tags: " << md3header->ofs_tags <<endl;
         cout << "Ofs Surfaces: " << md3header->ofs_surfaces <<endl;
         cout << "Ofs End: " << md3header->ofs_eof <<endl;

   for(int i=0; i<md3header->num_frames; i++)
   {
      cout << "Min Bounds: " << frames[i].min_bounds << endl;
      cout << "Max Bounds: " << frames[i].max_bounds << endl;
      cout << "Local Origin: " << frames[i].local_origin << endl;
      cout << "Radius: " << frames[i].radius << endl;
      cout << "Name: " << frames[i].name << endl;
   }

   for (int m=0; m<surfaces->num_triangles; m++)
   {
      cout << "1. " << triangles[m].indexes[0] <<endl;
      cout << "2. " << triangles[m].indexes[1] <<endl;
      cout << "3. " << triangles[m].indexes[2] <<endl;
   }

   this->num_triangles = surfaces->num_triangles;
      cout << surfaces->num_triangles << endl;

   for (int j=0; j<md3header->num_surfaces; j++)
   {
      cout << "Ident: " << surfaces[j].ident << endl;
      cout << "Name: " << surfaces[j].name <<endl;
      cout << "Flags: " << surfaces[j].flags <<endl;
      cout << "Num Frames: " << surfaces[j].num_frames <<endl;
      cout << "Num Shaders: " << surfaces[j].num_shaders <<endl;
      cout << "Num Vertices: " << surfaces[j].num_verts <<endl;
      cout << "Num Triangles: " << surfaces[j].num_triangles <<endl;
      cout << "Offset Triangles: " << surfaces[j].ofs_triangles <<endl;
      cout << "Offset Shaders: " << surfaces[j].ofs_shaders <<endl;
      cout << "Offset st: " << surfaces[j].ofs_st <<endl;
      cout << "Offset xyznormal: " << surfaces[j].ofs_xyznormal << endl;
      cout << "Offset End: " << surfaces[j].ofs_end <<endl;
   }
}

GameObject::~GameObject()
{
   //TODO: Some stuff
}


      void GameObject::draw() {

         cout << this->num_triangles << endl;
         glBegin(GL_TRIANGLES);
            for(int i=0; i<this->num_triangles;i++) {
                  glVertex3f(this->triangles[i].indexes[0] /100000000,this->triangles[i].indexes[1] /100000000,this->triangles[i].indexes[2] /1000000000);
               }

               glEnd();
}




Any help to get this working would be extremely helpful. Also I'm not too sure on the "void GameObject::draw" part so help with that would be great too, but it had worked before so it's not so important.




Top
                 

Mentor
Mentor
Joined: 12 Mar 2005
Posts: 3958
PostPosted: 02-01-2010 09:47 AM           Profile Send private message  E-mail  Edit post Reply with quote


Any reason to use (c|m)alloc and array pointers instead of new and std::vector?

As to why it crashes... hard to tell. Load it in gdb and do a backtrace (`bt`) after the crash.




Top
                 

Recruit
Recruit
Joined: 11 Jan 2010
Posts: 5
PostPosted: 02-09-2010 05:26 AM           Profile   Send private message  E-mail  Edit post Reply with quote


Right, I've found out that it's the reading in of the triangle data that is crashing the window. And the output out... Really not sure how to read this information in as the num_triangles is not within the md3_header... so I have to reference to the surface_header. I've changed this to:

Code:
this->triangles = (md3_triangle_header *)
            calloc(this->num_triangles,sizeof(struct md3_surface_header));
         md3file.seekg(this->surfaces->ofs_triangles, ios::beg);
         md3file.read((char *)triangles,sizeof (struct md3_triangle_header)* surfaces->num_triangles);


This, once again is crashing the window applet. :( Also, I think it's wrong.

The rest all works and outputs the information correctly, so this is the only thing I'm stuck on right now and I would really appreciate help to get the program to read in the information (and obviously print out to check if it works :P).

:)




Top
                 

Mentor
Mentor
Joined: 12 Mar 2005
Posts: 3958
PostPosted: 02-09-2010 05:48 AM           Profile Send private message  E-mail  Edit post Reply with quote


You mean this->num_triangles isn't initialized before you reference it?




Top
                 

Recruit
Recruit
Joined: 11 Jan 2010
Posts: 5
PostPosted: 02-09-2010 06:53 AM           Profile   Send private message  E-mail  Edit post Reply with quote


I'm not too sure. I'm trying to read in the data as with the other parts (verts, tags, surfaces etc) but these are in the md3_header of the header file whereas the triangles is referenced in the surface_header.

Basically, I'm just not sure how to get the data for the triangles to be read in so that it can be displayed.




Top
                 

Mentor
Mentor
Joined: 12 Mar 2005
Posts: 3958
PostPosted: 02-09-2010 08:13 PM           Profile Send private message  E-mail  Edit post Reply with quote


Selphie142 wrote:
I'm not too sure.

This is always the wrong answer when it comes to programming. :)

num_triangles is part of the surface header so step through your code with a debugger and make sure it is read correctly. BTW, what exactly do you mean when you say 'window applet'?




Top
                 

Recruit
Recruit
Joined: 23 May 2010
Posts: 1
PostPosted: 06-10-2010 01:43 PM           Profile Send private message  E-mail  Edit post Reply with quote


And what, if to us to look at this question from other point of view?




Top
                 
Quake3World.com | Forum Index | Programming Discussion


Post new topic Reply to topic


cron
Quake3World.com
© ZeniMax. Zenimax, QUAKE III ARENA, Id Software and associated trademarks are trademarks of the ZeniMax group of companies. All rights reserved.
This is an unofficial fan website without any affiliation with or endorsement by ZeniMax.
All views and opinions expressed are those of the author.