www.pudn.com > 3DmaxSLoader.rar > 3dsReader.cpp
// 3dsReader.cpp: implementation of the C3dsReader class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "3DSLoader.h"
#include "3dsReader.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
C3dsReader::C3dsReader()
{
}
C3dsReader::~C3dsReader()
{
}
// 将块的内容读入块结构中
int C3dsReader::Read3DSChunk(FILE* fp, Chunk3DS& chunk)
{
if (!ReadUShort(fp, chunk.id)) return FALSE;
if (!ReadLong(fp, chunk.len)) return FALSE;
return TRUE;
}
// 读入字符串,如果字符串的长度大于缓冲区,则截去多余的部分
int C3dsReader::Read3DSString(FILE* fp, char* name, int len /*= 256*/)
{
int c;
for (int i=0; (c = fgetc(fp)) != EOF && c != '\0'; i++) {
if (i < len) {
name[i] = c;
}
}
if (i < len) {
name[i] = '\0';
} else {
name[len-1] = '\0';
}
return (c != EOF);
}
// 读入子块
int C3dsReader::ReadPercentage(FILE* fp, float& value)
{
Chunk3DS chunk;
long chunkStart = ftell(fp);
if (!Read3DSChunk(fp, chunk)) return FALSE;
if (chunk.id == INT_PERCENTAGE)
{
short svalue;
if (!ReadShort(fp, svalue)) return FALSE;
value = (float) svalue/ (float) 1.0;//100.0
return TRUE;
} else if (chunk.id == FLOAT_PERCENTAGE)
{
if (!ReadFloat(fp, value)) return FALSE;
return TRUE;
}
fseek(fp, chunkStart + chunk.len, SEEK_SET);
return FALSE;
}
// 读入颜色定义
int C3dsReader::ReadColor(FILE* fp, float& red, float& green, float& blue)
{
Chunk3DS chunk;
long chunkStart = ftell(fp);
unsigned char tmp;
if (!Read3DSChunk(fp, chunk)) return FALSE;
switch (chunk.id)
{
case COLOR_F:
if (!ReadFloat(fp, red)) return FALSE;
if (!ReadFloat(fp, green)) return FALSE;
if (!ReadFloat(fp, blue)) return FALSE;
break;
case COLOR_24:
if (!ReadUByte(fp, tmp)) return FALSE;
red = (float) tmp / (float) 255.0;
if (!ReadUByte(fp, tmp)) return FALSE;
green = (float) tmp / (float) 255.0;
if (!ReadUByte(fp, tmp)) return FALSE;
blue = (float) tmp / (float) 255.0;
break;
default:
fseek(fp, chunkStart + chunk.len, SEEK_SET);//将文件指针移到离文件头chunkStart + chunk.len个字节处
return FALSE;
}
return TRUE;
}
// 读入顶点
int C3dsReader::ReadPointArray (CTriObject* newchild, long fileSize, FILE *fp)
{
unsigned short count;
float value;
if (!ReadUShort(fp, count)) return FALSE;
float* x = new float[count];
float* y = new float[count];
float* z = new float[count];
if (x == NULL || y == NULL || z == NULL) return FALSE;
for (int i = 0; isetX(x, count);
newchild->setY(y, count);
newchild->setZ(z, count);
return count;
}
// 读入多边形
int C3dsReader::ReadFaceArray (CTriObject* newchild, long unsigned fileSize, FILE* fp)
{
unsigned short count = 0;
unsigned short value = 0;
BOOL error = FALSE;
// 读入数量
int* fac;
if (!ReadUShort(fp, count)) return FALSE;
fac = new int[count*3];
if (fac == NULL) return FALSE;
// 读入面
for (int i=0; isetFaces(fac, count*3);
return count*3;
}
// 读入对象所用的材质
int C3dsReader::ReadMeshMatGroup(CTriObject* newchild, MaterialDict* matdict, long fileSize, FILE* fp)
{
unsigned short count, face;
char name[256];
tMaterial* lookup;
long index = 0;
// 读入材质名称
if (!Read3DSString(fp, name, 256)) return FALSE;
// 在材质库中查找该材质
if ((lookup = matdict->Lookup(name)) != NULL)
{
index = newchild->addMaterial(lookup);
}
// 读入该材质映射的面的数量
if (!ReadUShort(fp, count)) return FALSE;
while (count-- > 0)
{
if (!ReadUShort(fp, face)) return FALSE;
if (index != -1) newchild->addMaterialFace(face, index);
}
return TRUE;
}
// 读入对象数据
int C3dsReader::ReadTriObject(MaterialDict* matdict, long fileSize, FILE* fp, long triStart, long triSize, char* groupName)
{
Chunk3DS chunk;
long chunkStart = ftell(fp);
int verticecount = 0;
int facecount = 0;
int matcount = 0;
static int id = 1;
CTriObject* newchild = new CTriObject();
// 读入并填充数据
while (chunkStart < triStart + triSize && Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case POINT_ARRAY:
verticecount = ReadPointArray(newchild, fileSize, fp);
if (verticecount == FALSE) return FALSE;
break;
case FACE_ARRAY:
facecount = ReadFaceArray(newchild, fileSize, fp);
if (facecount == FALSE) return FALSE;
break;
case MSH_MAT_GROUP:
if (!ReadMeshMatGroup(newchild, matdict, fileSize, fp)) return FALSE;
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
// 设置名称,并将本项目添加到列表中
newchild->setName(groupName);
newchild->setId(id);
DaList->add(newchild);
id++;
return TRUE;
}
// 读入对应名称的对象块,其它名称的块将忽略
int C3dsReader::ReadNamedObject(MaterialDict* matdict, long fileSize, long namedStart, long namedSize, FILE* fp)
{
char groupName[256];
Chunk3DS chunk;
long chunkStart;
if (!Read3DSString(fp, groupName, 256)) return FALSE;
chunkStart = ftell(fp);
while (chunkStart < namedStart+namedSize && Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case N_TRI_OBJECT:
if (!ReadTriObject(matdict, fileSize, fp, chunkStart, chunk.len, groupName)) return FALSE;
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
return TRUE;
}
// 读入材质定义,并将其添加到材质库中
int C3dsReader::ReadMatEntry(MaterialDict* matdict, long fileSize, long matStart, long matSize, FILE* fp)
{
long chunkStart = ftell(fp);
Chunk3DS chunk;
char name[256];
float red, green, blue;
float percentage;
tMaterial material;
while (chunkStart < matStart + matSize &&
Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case MAT_NAME:
if (!Read3DSString(fp, name, 256)) return FALSE;
break;
case MAT_AMBIENT:
if (!ReadColor(fp, red, green, blue)) return FALSE;
material.ambientColor[0] = red;
material.ambientColor[1] = green;
material.ambientColor[2] = blue;
break;
case MAT_DIFFUSE:
if (!ReadColor(fp, red, green, blue)) return FALSE;
material.diffuseColor[0] = red;
material.diffuseColor[1] = green;
material.diffuseColor[2] = blue;
break;
case MAT_SPECULAR:
if (!ReadColor(fp, red, green, blue)) return FALSE;
material.specularColor[0] = red;
material.specularColor[1] = green;
material.specularColor[2] = blue;
break;
case MAT_SHININESS:
if (!ReadPercentage(fp, percentage)) return FALSE;
material.shininess = ((float)percentage)/100.0f;
break;
case MAT_TRANSPARENCY:
if (!ReadPercentage(fp, percentage)) return FALSE;
material.transparency = ((float)percentage)/100.0f;
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
matdict->Add(name, material);
return TRUE;
}
// 读入最高级的对象数据
int C3dsReader::ReadMDATA(MaterialDict* matdict, long fileSize, long mdataStart, long mdataSize, FILE* fp)
{
long chunkStart = ftell(fp);
Chunk3DS chunk;
unsigned long version;
float scale;
while (chunkStart < mdataStart + mdataSize && Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case MESH_VERSION:
if (!ReadULong(fp, version))
{
return FALSE;
}
break;
case MAT_ENTRY:
if (!ReadMatEntry(matdict, fileSize, chunkStart, chunk.len, fp))
{
return FALSE;
}
break;
case MASTER_SCALE:
if (!ReadFloat(fp, scale))
{
return FALSE;
}
break;
case NAMED_OBJECT:
if (!ReadNamedObject(matdict, fileSize, chunkStart, chunk.len, fp))
{
return FALSE;
}
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
return TRUE;
}
// 读入3DS文件
int C3dsReader::Read3DSFile(long fileSize, long fileStart, long fileLen, FILE* fp)
{
long chunkStart = ftell(fp);
Chunk3DS chunk;
MaterialDict *matdict = new MaterialDict();
unsigned long version;
while (chunkStart < fileStart + fileLen && Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case M3D_VERSION:
if (!ReadULong(fp, version))
{
if (matdict != NULL) delete matdict;
return FALSE;
}
break;
case MDATA:
if (!ReadMDATA(matdict, fileSize, chunkStart, chunk.len, fp))
{
if (matdict != NULL) delete matdict;
return FALSE;
}
break;
case KFDATA:
if (!ReadKFDATA(fileSize, chunkStart, chunk.len, fp))
{
if (matdict != NULL) delete matdict;
return FALSE;
}
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
if (matdict != NULL) delete matdict;
return TRUE;
}
// 验证当前的文件是否是3DS文件
int C3dsReader::Is3DSFile(FILE* fp)
{
Chunk3DS chunk;
long pos = ftell(fp);
if (!Read3DSChunk(fp, chunk))
{
fseek(fp, pos, SEEK_SET);
return FALSE;
}
fseek(fp, pos, SEEK_SET);
return (chunk.id == M3DMAGIC);
}
// 读入一个3DS文件
BOOL C3dsReader::Reader( char* filename, CTriList* _list)
{
FILE* fp;
long fileSize;
Chunk3DS chunk;
DaList = _list;
// 以“二进制”的方式打开一个3DS文件
if ((fp = fopen(filename, "rb")) != NULL)
{
long chunkStart = ftell(fp);
// 获得文件大小
fseek(fp, 0, SEEK_END);
fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
// 验证文件类型
if (!Is3DSFile(fp))
{
return FALSE;
}
// 循环所有的块
while (chunkStart < fileSize &&
Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case M3DMAGIC:
if (!Read3DSFile(fileSize, chunkStart, chunk.len, fp))
{
fclose(fp);
return FALSE;
}
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
fclose(fp);
}
else
return FALSE;
return TRUE;
}
int C3dsReader::ReadKFDATA(long fileSize, long kfdataStart, long kfdataSize, FILE * fp)
{
long chunkStart = ftell(fp);
Chunk3DS chunk;
short version;
long kflength;
long kfstart;
long kfend;
char name[256];
while (chunkStart < kfdataStart + kfdataSize && Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case KFHDR:
if (!ReadShort(fp,version)) return FALSE;
if (!Read3DSString(fp, name, 256)) return FALSE;
if (!ReadLong(fp, kflength)) return FALSE;
break;
case KFSEG:
if (!ReadLong(fp, kfstart)) return FALSE;
if (!ReadLong(fp, kfend)) return FALSE;
break;
case OBJECT_NODE_TAG:
ReadKFObjectNode(fileSize, chunkStart, chunk.len, fp);
fseek(fp, chunkStart + chunk.len, SEEK_SET);
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
return TRUE;
}
int C3dsReader::ReadKFObjectNode(long fileSize, long nodeStart, long nodeSize, FILE * fp)
{
long chunkStart = ftell(fp);
Chunk3DS chunk;
short nodeid;
char nodeName[256];
tVector pivot;
while (chunkStart < nodeStart + nodeSize && Read3DSChunk(fp, chunk))
{
switch (chunk.id)
{
case NODE_ID:
if(!ReadShort(fp, nodeid)) return false;
fseek(fp, chunkStart + chunk.len, SEEK_SET);
break;
case NODE_HDR:
if (!Read3DSString(fp, nodeName, 256)) return FALSE;
fseek(fp, chunkStart + chunk.len, SEEK_SET);
break;
case PIVOT:
if (!ReadFloat(fp, pivot.x)) return FALSE;
if (!ReadFloat(fp, pivot.y)) return FALSE;
if (!ReadFloat(fp, pivot.z)) return FALSE;
fseek(fp, chunkStart + chunk.len, SEEK_SET);
break;
case POS_TRACK_TAG:
if(!ReadKFTrackTag(fileSize, chunkStart, chunk.len, fp, nodeName, &pivot, chunk)) return FALSE;
fseek(fp, chunkStart + chunk.len, SEEK_SET);
break;
case ROT_TRACK_TAG:
if(!ReadKFTrackTag(fileSize, chunkStart, chunk.len, fp, nodeName, &pivot, chunk)) return FALSE;
fseek(fp, chunkStart + chunk.len, SEEK_SET);
break;
case SCL_TRACK_TAG:
if(!ReadKFTrackTag(fileSize, chunkStart, chunk.len, fp, nodeName, &pivot, chunk)) return FALSE;
fseek(fp, chunkStart + chunk.len, SEEK_SET);
break;
default:
// 忽略一些不需要的块
fseek(fp, chunkStart + chunk.len, SEEK_SET);
}
chunkStart = ftell(fp);
}
return TRUE;
}
int C3dsReader::ReadKFTrackTag(long fileSize, long tagStart, long tagSize, FILE * fp, char * nodeName, tVector* pivot, Chunk3DS chunk)
{
long numkeys;
short rflags;
short trflags;
long trtmin,trtmax;
CTriObject* current;
Key key;
// 获得当前的物体
current = DaList->getObjectByName(nodeName);
if(current == NULL) return FALSE;
// 设置转动轴
current->setPivotPoint(pivot);
ReadShort(fp, trflags);
ReadLong(fp, trtmin);
ReadLong(fp, trtmax);
ReadLong(fp, numkeys);
for (int i=0; i