C:Load3DS - GPWiki

来源:百度文库 编辑:神马文学网 时间:2024/05/01 02:43:05
C:Load3DS
http://gpwiki.org/index.php/C:Load3DS
From GPWiki
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 itgoes. There is no rendering function, you can get the object data fromthe 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);
void Get3fVector(int offset,float &x1,float &x2,float &x3);
void Get3Vector(int offset,unsigned short &x1,unsigned short &x2,unsigned short &x3);
void Get2fVector(int offset,float &x1,float &x2);
};
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;
char bVal;
short Val,Val2;
float fVal,fVal2,fVal3;
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{
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 0x0010:
Get3fVector(Offset+6,fVal,fVal2,fVal3);
printf("Chunk 0010 (RGB) %f %f %f\nOffset %d\n",fVal,fVal2,fVal3,Info.Size);
Offset+=Info.Size;
break;
case 0x0013:
Get3fVector(Offset+6,fVal,fVal2,fVal3);
printf("Chunk 0013 (gamma corrected) %f %f %f\nOffset %d\n",fVal,fVal2,fVal3,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) %f\nOffset %d\n",&data[Offset+6],Info.Size);
Offset+=Info.Size;
break;
case 0x1400: //Shadow map bias
memcpy(&fVal,&data[Offset+6],4);
printf("Chunk 1400 (shadow map bias) %f\nOffset %d\n",fVal,Info.Size);
Offset+=Info.Size;
break;
case 0x1420:// shadow map size
memcpy(&Val,&data[Offset+6],2);
printf("Chunk 1420 (shadow map size) %d\nOffset %d\n",Val,Info.Size);
Offset+=Info.Size;
break;
case 0x1450: //shadow map sample range
memcpy(&fVal,&data[Offset+6],4);
printf("Chunk 1450 (shadow map sample range) %f\nOffset %d\n",fVal,Info.Size);
Offset+=Info.Size;
break;
case 0x1460: //raytrace bias
memcpy(&fVal,&data[Offset+6],4);
printf("Chunk 1460 (Raytrace bias) %f\nOffset %d\n",fVal,Info.Size);
Offset+=Info.Size;
break;
case 0x1470:
printf("Chunck 1470 (use raytrace)\nOffset %d\n",6);
Offset+=6;
break;
case 0x2100: //Ambient color
printf("Chunk 2100 (ambient color)\nOffset %d\n",Info.Size);
Offset+=6;
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)
{
Get3fVector(LOff,Mesh[MeshDex].vtx[Loop].x,Mesh[MeshDex].vtx[Loop].y,Mesh[MeshDex].vtx[Loop].z);
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)
{
Get3Vector(LOff,Mesh[MeshDex].face[Loop].p1,Mesh[MeshDex].face[Loop].p2,Mesh[MeshDex].face[Loop].p3);
memcpy(&Val2,&data[LOff+6],2);
printf("X: %d, Y: %d, Z: %d (",Mesh[MeshDex].face[Loop].p1,Mesh[MeshDex].face[Loop].p2,Mesh[MeshDex].face[Loop].p3);
if (Val2&0x01) printf("AC ");
if (Val2&0x02) printf("BC ");
if (Val2&0x04) printf("AB ");
printf("visible)\n");
}
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 4140 (UV Map List) %d Vertices\nOffset %d\n",Val,Info.Size);
Mesh[MeshDex].nUV=Val;
Mesh[MeshDex].UV = new UVCoord[Val+1];
for(Loop=0,LOff=Offset+8;Loop!=Val;++Loop,LOff+=8)
{
Get2fVector(LOff,Mesh[MeshDex].UV[Loop].U,Mesh[MeshDex].UV[Loop].V);
printf("U: %f, V: %f,\n",Mesh[MeshDex].UV[Loop].U,Mesh[MeshDex].UV[Loop].V);
}
Offset+=Info.Size;
break;
case 0x4160: //local coordinate system
printf("Chunk 4160 (Local coordinate system)\nOffset %d\n",Info.Size);
Get3fVector(Offset+6,fVal,fVal2,fVal3);
printf("X1 vector: %f %f %f\n",fVal,fVal2,fVal3);
Get3fVector(Offset+18,fVal,fVal2,fVal3);
printf("X2 vector: %f %f %f\n",fVal,fVal2,fVal3);
Get3fVector(Offset+30,fVal,fVal2,fVal3);
printf("X3 vector: %f %f %f\n",fVal,fVal2,fVal3);
Get3fVector(Offset+42,fVal,fVal2,fVal3);
printf("O vector: %f %f %f\n",fVal,fVal2,fVal3);
Offset+=Info.Size;
break;
case 0x4165:
memcpy(&bVal,&data[Offset+6],1);
printf("Chunk 4165 (Object color in 3d editor) %d\nOffset %d\n",bVal,Info.Size);
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 0xA052: // Material - Transperancy fall off
Get2fVector(Offset+6,fVal,fVal2);
printf("Chunk A052 (Material trasn. falloff) %f %f\nOffset %d\n",fVal,fVal2,Info.Size);
Offset+=Info.Size;
break;
case 0xA053: // Reflection blur percent
Get2fVector(Offset+6,fVal,fVal2);
printf("Chunk A053 (Material reflection blur percent) %f %f\nOffset %d\n",fVal,fVal2,Info.Size);
Offset+=Info.Size;
break;
case 0xA081: //two sided
printf("Chunk A081 (Mat. Two sided)\nOffset %d\n",6);
Offset+=6;
break;//Info.Size;
case 0xA087: // Wire thickness
memcpy(&fVal,&data[Offset+6],4);
printf("Chunk A087 (Mat. Wire Thickness) %f\nOffset %d\n",fVal,Info.Size);
Offset+=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{
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;
}
void Obj3DS::Get3fVector(int offset,float &x1,float &x2,float &x3)
{
memcpy(&x1,&data[offset],4);
memcpy(&x2,&data[offset+4],4);
memcpy(&x3,&data[offset+8],4);
}
void Obj3DS::Get3Vector(int offset,unsigned short &x1,unsigned short &x2,unsigned short &x3)
{
memcpy(&x1,&data[offset],2);
memcpy(&x2,&data[offset+2],2);
memcpy(&x3,&data[offset+4],2);
}
void Obj3DS::Get2fVector(int offset,float &x1,float &x2)
{
memcpy(&x1,&data[offset],4);
memcpy(&x2,&data[offset+4],4);
}