C:Load3DS
From GPWiki
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; } |


