C:Load3DS

From GPWiki

(Redirected from Load3DS Cpp)

Files:GUITutorial_warn.gif The Game Programming Wiki has moved! Files:GUITutorial_warn.gif

The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server.

However, the GPWiki forums are still active! Come say hello.

This is not finished code, it's a work in progress that answers a question in the forum.

Feel free to fix it up, tweak it or point and laugh.

The code loads a 3DS file, dumping the info to the screen as it goes. There is no rendering function, you can get the object data from the vtx, norm and UVCoord arrays after loading if required.

struct ChunkInfo
 {
  unsigned short ID;
  int Size;
 };
 
struct Vertex
 {
  float x,y,z;
 };
 
struct Face
 {
  unsigned short p1,p2,p3;
 };
 
struct UVCoord
 {
  float U,V;
 };
 
struct ObjMesh
 {
  Vertex *vtx;
  Vertex *norm;
  int nVtx,nFace,nUV;
  Face *face;
  UVCoord *UV;
  char MatName[64];
 };
 
struct ObjMatl
 {
  char Name[64];
  unsigned int Red,Green,Blue;
  char TexName[64];
  int Smooth;
 };
 
 
class Obj3DS
 {
  public:
 
   int fSize;
   unsigned char *data;
   int nMesh,nMatl;
 
   ObjMesh *Mesh;
   ObjMatl *Matl;
 
   Obj3DS();
   ~Obj3DS();
   int CountParts(int DataLen);
   int Load(char *fName);
   ChunkInfo GetChunkInfo(int Offset);
 };
 
Obj3DS::Obj3DS()
 {
  fSize=0;
  data=NULL;
  Mesh=NULL;
  Matl=NULL;
 }
 
Obj3DS::~Obj3DS()
 {
   if(data!=NULL)
    {
     delete [] data;
     data=NULL;
    }
  
   if(Mesh!=NULL) // Still to clear vertex, norm , etc allocation
    {
     delete [] Mesh;
     Mesh=NULL;
    }
 
   if(Matl!=NULL)
    {
     delete [] Matl;
     Matl=NULL;
    }
 }
 
int Obj3DS::Load(char *fName)
 {
  FILE *in;
  ChunkInfo Info;
  int Offset,SubChunkSize,Value,MatDex,MeshDex,Loop,LOff;
  short Val;
  float fVal;
  bool CopyVal=FALSE;
 
  MatDex=-1;
  MeshDex=-1;
 
  in=fopen(fName,"rb");
 
   if(in==NULL)
    return false;
 
  // Get filelength
  fseek(in,0,SEEK_END);
  fSize=ftell(in);
  fseek(in,0,SEEK_SET);
 
   // Allocate memory
   if(data!=NULL)
    delete [] data;
 
  data=new unsigned char[fSize];
 
   if(data==NULL)
    {
     fclose(in);
     return false;
    }
 
  // Read data
  fread(data,1,fSize,in);
 
  fclose(in);
 
  // Check header
  Offset=0;
  Info=GetChunkInfo(Offset);
 
   if(Info.ID!=0x4D4D)
    return false;
 
   if(Info.Size!=fSize)
    return false;
 
  CountParts(fSize);
 
  Mesh=new ObjMesh[nMesh];
  Matl=new ObjMatl[nMatl];
 
  Offset=6;
 
   while(Offset<fSize)
    {
     Info=GetChunkInfo(Offset);
 
      switch(Info.ID)
       {
        case 0x0002: // Version
         {
          memcpy(&Value,&data[Offset+6],4);
          printf("Chunk 0002 (Version) - %d\nOffset %d\n",Value,Info.Size);
          Offset+=Info.Size;
          break;
         }
 
        case 0x0011: // RGB1
         {
          printf("Chunk 0011 (RGB1) %d %d %d\nOffset %d\n",data[Offset+6]
                                                           ,data[Offset+7]
                                                           ,data[Offset+8]
                                                           ,Info.Size);
 
           if(CopyVal)
            {
             Matl[MatDex].Red=data[Offset+6];
             Matl[MatDex].Green=data[Offset+7];
             Matl[MatDex].Blue=data[Offset+8];
             CopyVal=FALSE;
            }
 
 
          Offset+=Info.Size;
          break;
         }
 
        case 0x0012: // RGB2
         {
          printf("Chunk 0012 (RGB2) %d %d %d\nOffset %d\n",data[Offset+6]
                                                           ,data[Offset+7]
                                                           ,data[Offset+8]
                                                           ,Info.Size);
          Offset+=Info.Size;
          break;
         }
 
 
        case 0x0030: // Quantity value for parent chunks
         {
          memcpy(&Val,&data[Offset+6],2);
          printf("Chunk 0030 (Qty Value) %d\nOffset %d\n",Val,Info.Size);
          Offset+=Info.Size;
          break;
         }
 
        case 0x0100: // Config (Ignore)
         printf("Chunk 0100 (Config)\nOffset %d\n",Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0x3D3D: // Start of Obj
         {
          printf("Chunk 3D3D (Start of Obj)\nOffset %d\n",Info.Size);
          SubChunkSize=Info.Size+Offset; // Set end limit for subchunk
          Offset+=6;
          break;
         }
 
        case 0x3D3E: // Editor config (Ignore)
         printf("Chunk 3D3E (Editor Config)\nOffset %d\n",Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0x4000: // Start of Mesh
         printf("Chunk 4000 (Start of Mesh) - %s\nOffset %d\n",&data[Offset+6],Info.Size);
         Offset+=6;
          while(data[Offset]!=NULL) // Seek end of string
           Offset++;
 
          Offset++; // One more to move past the NULL
          MeshDex++;
         break;
 
        case 0x4100: // Mesh data
         printf("Chunk 4100 (Mesh Data)\nOffset %d\n",Info.Size);
         Offset+=6;
         break;
 
        case 0x4110: // Vertex List
         memcpy(&Val,&data[Offset+6],2);
         printf("Chunk 4110 (Vertex List) %d Vertices\nOffset %d\n",Val,Info.Size);
         Mesh[MeshDex].nVtx=Val;
         Mesh[MeshDex].vtx = new Vertex[Val+1];
          for(Loop=0,LOff=Offset+8;Loop!=Val;++Loop,LOff+=12)
           {
            memcpy(&(Mesh[MeshDex].vtx[Loop].x),&data[LOff],4);
            memcpy(&(Mesh[MeshDex].vtx[Loop].y),&data[LOff+4],4);
            memcpy(&(Mesh[MeshDex].vtx[Loop].z),&data[LOff+8],4);
            printf("x - %f, Y - %f, Z - %f\n",Mesh[MeshDex].vtx[Loop].x,Mesh[MeshDex].vtx[Loop].y,Mesh[MeshDex].vtx[Loop].z);
           }
         Offset+=Info.Size;
         break;
 
        case 0x4111: // Vertex Options
         printf("Chunk 4111 (Vertex Options)\nOffset %d\n",Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0x4120: // Face List
         memcpy(&Val,&data[Offset+6],2);
         printf("Chunk 4120 (Face List) %d polys\nOffset %d\n",Val,Info.Size);
         Mesh[MeshDex].nFace=Val;
         Mesh[MeshDex].face = new Face[Val+1];
          for(Loop=0,LOff=Offset+8;Loop!=Val;++Loop,LOff+=8)
           {
            memcpy(&(Mesh[MeshDex].face[Loop].p1),&data[LOff],2);
            memcpy(&(Mesh[MeshDex].face[Loop].p2),&data[LOff+2],2);
            memcpy(&(Mesh[MeshDex].face[Loop].p3),&data[LOff+4],2);
            printf("x - %d, Y - %d, Z - %d\n",Mesh[MeshDex].face[Loop].p1,Mesh[MeshDex].face[Loop].p2,Mesh[MeshDex].face[Loop].p3);
           }
         Offset+=Info.Size;
         break;
 
        case 0x4130: // Material Desc
         Offset+=Info.Size;
         break;
 
        case 0x4140: // UV Map List
         memcpy(&Val,&data[Offset+6],2);
         printf("Chunk 4120 (UV Map List)\nOffset %d\n",Info.Size);
         Mesh[MeshDex].nUV=Val;
         Mesh[MeshDex].UV = new UVCoord[Val+1];
          for(Loop=0,LOff=Offset+8;Loop!=Val;++Loop,LOff+=8)
           {
            memcpy(&(Mesh[MeshDex].UV[Loop].U),&data[LOff],4);
            memcpy(&(Mesh[MeshDex].UV[Loop].V),&data[LOff+4],4);
            printf("U - %f, V - %f,\n",Mesh[MeshDex].UV[Loop].U,Mesh[MeshDex].UV[Loop].V);
           }
         Offset+=Info.Size;
         break;
 
        case 0xA000: // Material Name
         printf("Chunk A000 (Material Name) - %s\nOffset %d\n",&data[Offset+6],Info.Size);
         lstrcpy(Matl[MatDex].Name,(LPSTR)&data[Offset+6]);
         Offset+=Info.Size;
         break;
 
        case 0xA010: // Material - Ambient Color
         printf("Chunk A010 (Material - Amb Col)\nOffset %d\n",Info.Size);
         Offset+=6;//Info.Size;
         break;
 
        case 0xA020: // Material - Diffuse Color
         printf("Chunk A020 (Material - Dif Col)\nOffset %d\n",Info.Size);
         CopyVal=TRUE;
         Offset+=6;//Info.Size;
         break;
 
        case 0xA030: // Material - Spec Color
         printf("Chunk A030 (Material - Spec Col)\nOffset %d\n",Info.Size);
         Offset+=6;//Info.Size;
         break;
 
        case 0xA040: // Material - Shininess
         printf("Chunk A040 (Material - Shininess)\nOffset %d\n",Info.Size);
         Offset+=6;//Info.Size;
         break;
 
        case 0xA041: // Material - Shine Strength
         printf("Chunk A041 (Material - Shine Strength)\nOffset %d\n",Info.Size);
         Offset+=6;//Info.Size;
         break;
 
        case 0xA050: // Material - Transparency
         printf("Chunk A050 (Material - Transparency)\nOffset %d\n",Info.Size);
         Offset+=6;//Info.Size;
         break;
 
        case 0xA100: // Material - Type (Flat,Gourad, Phong, Metal)
         memcpy(&Val,&data[Offset+6],2);
         printf("Chunk A100 (Material Type) %d\nOffset %d\n",Val,Info.Size);
         Matl[MatDex].Smooth=Val;
         Offset+=Info.Size;
         break;
 
        case 0xA200: // Material - Start of Texture Info
         printf("Chunk A200 (Material Tex Map)\nOffset %d\n",Info.Size);
         Offset+=6;
         break;
 
        case 0xA300: // Material - Texture Name
         printf("Chunk A300 (Material Tex Map Name) %s\nOffset %d\n",&data[Offset+6],Info.Size);
         lstrcpy(Matl[MatDex].TexName,(LPSTR)&data[Offset+6]);
         Offset+=Info.Size;
         break;
 
        case 0xA351: // Material - Texture Options
         memcpy(&Val,&data[Offset+6],2);
         printf("Chunk A351 (Material Tex Options) %d\nOffset %d\n",Val,Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0xA354: // Material - Texture U Scale
         memcpy(&fVal,&data[Offset+6],4);
         printf("Chunk A354 (Material Tex U Scale) %f\nOffset %d\n",fVal,Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0xA356: // Material - Texture V Scale
         memcpy(&fVal,&data[Offset+6],4);
         printf("Chunk A356 (Material Tex V Scale) %f\nOffset %d\n",fVal,Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0xA35A: // Material - Texture V Offset
         memcpy(&fVal,&data[Offset+6],4);
         printf("Chunk A35A (Material Tex V Offset) %f\nOffset %d\n",fVal,Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0xA35C: // Material - Texture V Offset
         memcpy(&fVal,&data[Offset+6],4);
         printf("Chunk A35C (Material Tex Rotation) %f\nOffset %d\n",fVal,Info.Size);
         Offset+=Info.Size;
         break;
 
        case 0xAFFF: // Material Start
         printf("Chunk AFFF (Start of Material)\nOffset %d\n",Info.Size);
         MatDex++;
         Offset+=6;
         break;
 
        default:
         printf("Chunk %04X (Unknown)\nOffset %d\n",Info.ID,Info.Size);
         Offset+=Info.Size;
         break;
       }
 
    }
 
  return true;
 }
 
 
int Obj3DS::CountParts(int DataLen)
 {
  long Offset=6;
  ChunkInfo Info;
  nMesh=0,nMatl=0;
 
 
   while(Offset<DataLen)
    {
     Info=GetChunkInfo(Offset);
 
      switch(Info.ID)
       {
        case 0x3D3D: // Start of Obj
         {
          Offset+=6;
          break;
         }
 
        case 0x4000: // Start of Mesh
          nMesh++;
          Offset+=Info.Size;
         break;
 
        case 0xAFFF: // Start of Material
         nMatl++;
         Offset+=Info.Size;
         break;
 
 
        default:
         Offset+=Info.Size;
         break;
       }
 
    }
 
  return nMesh;
 }
 
 
ChunkInfo Obj3DS::GetChunkInfo(int Offset)
 {
  ChunkInfo Chunk;
  memcpy(&Chunk.ID,&data[Offset],2);
  memcpy(&Chunk.Size,&data[Offset+2],4);
  return Chunk;
 }