// Our .3DS file that we'll use for testing.
#define
FILENAME "cube.3ds"
/***************************************************************************/
#include
<stdio.h>
// I've put the chunk defenitions in a seperate file on there own, called
// chunkdetails.h, which we'll include here.
#include
"chunkdetails.h"
/***************************************************************************/
/*
*/
/* Write feedback information to a file - so we can understand what is
*/
/* really happening inside that .3ds file.
*/
/*
*/
/***************************************************************************/
void
abc(char *s)
{
FILE *fp;
fp
= fopen("t.txt", "a+");
fprintf(fp, "%s", s);
fclose(fp);
}
/***************************************************************************/
/*
*/
/* Some user functions to make the reading of the .3ds file easier
*/
/*
*/
/***************************************************************************/
/* Helper Functions that make our parsing of the chunks easier
*/
/***************************************************************************/
struct
stChunk
{
unsigned short
ID;
unsigned int
length;
unsigned int
bytesRead;
};
void
ReadChunk(FILE*fp, stChunk *pChunk)
{
unsigned short
ID = 0;
unsigned int
bytesRead = 0;
unsigned int
bChunkLength = 0;
bytesRead = fread(&ID, 1, 2, fp);
bytesRead += fread(&bChunkLength, 1, 4, fp);
pChunk->ID = ID;
pChunk->length = bChunkLength;
pChunk->bytesRead = bytesRead;
}
void
SkipChunk(FILE*fp, stChunk *pChunk)
{
int buffer[50000] = {0};
fread(buffer, 1, pChunk->length - pChunk->bytesRead, fp);
}
void
DisplayChunkInfo(stChunk* pChunk)
{
char buf[1000] = {0};
sprintf(buf, "Chunk ID: 0x %04x Size of Chunk: %u\n",
pChunk->ID, pChunk->length);
abc(buf);
}
/***************************************************************************/
/*
*/
/* Helper Fuction, simply reads in the string from the file pointer, until
*/
/* a null is reached, then returns how many bytes was read.
*/
/*
*/
/***************************************************************************/
int
GetString(FILE *fp)
{
int index = 0;
char buffer[100] = {0};
fread(buffer, 1, 1, fp);
while( *(buffer + index++) != 0)
{
fread(buffer + index, 1, 1, fp);
}
abc(buffer);
abc("\n");
return (int)(strlen(buffer) + 1);
}
void
ParseChunk(FILE *fp, stChunk* Chunk); // forward declaration
int
GetString(FILE* fp); // forward
declaration
/***************************************************************************/
/*
*/
/* This little function reads the matrial data for our individual object,
*/
/* So it determines which face references which material, in our material
*/
/* list.
*/
/*
*/
/***************************************************************************/
void
ReadMeshMaterials(FILE*fp, stChunk* Chunk)
{
abc("\n");
// Material Name Where Referencing
unsigned int
characterlen = GetString(fp);
Chunk->bytesRead += characterlen;
unsigned short
iNumFaces = 0;
Chunk->bytesRead += fread(&iNumFaces, 1, 2, fp);
unsigned short
*FaceAssignedThisMaterial = new
unsigned short[iNumFaces];
Chunk->bytesRead += fread(FaceAssignedThisMaterial, 1,
iNumFaces*sizeof(unsigned
short), fp);
char buf[1000] = {0};
sprintf(buf, "Material: FaceCount: %d\n",iNumFaces);
abc(buf);
for( int i=0;
i<iNumFaces; i++ )
{
sprintf(buf, "\tFaceAssignedThisMaterial: %d\n",FaceAssignedThisMaterial[i]);
abc(buf);
}
return;
}
/***************************************************************************/
/*
*/
/* We get all the faces...e.g. Triangle Index's into our vertex array, so
*/
/* we can actually put our shape together.
*/
/*
*/
/***************************************************************************/
void
ReadMeshFaces(FILE *fp, stChunk* Chunk)
{
unsigned int
iNumberFaces = 0; //= Chunk->length - 6;
Chunk->bytesRead += fread(&iNumberFaces, 1, 2, fp);
char buff[100];
sprintf(buff, "Number of Faces %u\n", iNumberFaces);
abc(buff);
// Each face is 3 points A TRIANGLE!..WOW
struct stFace{
unsigned short p1, p2, p3,
visibityflag; };
stFace *pFaces = new stFace[iNumberFaces];
Chunk->bytesRead += fread(pFaces, 1, iNumberFaces*sizeof(stFace),
fp);
for( int i=0;
i<iNumberFaces; i++ )
{
sprintf(buff, "\t Face: Index1: %d, Index2: %d, Index3 %d\n",
pFaces[i].p1, pFaces[i].p2,
pFaces[i].p3);
abc(buff);
}
delete pFaces;
// Our face material information is a sub-chunk.
ParseChunk(fp, Chunk);
}
/***************************************************************************/
/*
*/
/* You know all those x,y,z things...yup I mean vertices...well this reads
*/
/* them all in.
*/
/*
*/
/***************************************************************************/
void
ReadMeshVertices(FILE *fp, stChunk* Chunk)
{
unsigned int
iNumberVertices = 0;
Chunk->bytesRead += fread(&iNumberVertices, 1, 2, fp);
// e.g. 8 Vertices make up our simple box!
char buff[300];
sprintf(buff, "Number of Vertices %d\n", iNumberVertices);
abc(buff);
// Allocate Memory and dump our vertices to the
screen.
struct stVect{
float x, y, z; };
stVect *pVerts = new stVect[iNumberVertices];
Chunk->bytesRead += fread( (void*)pVerts, 1,
iNumberVertices*sizeof(stVect), fp);
for(int i=0;
i<iNumberVertices; i++)
{
sprintf(buff, "\t Vertices Point: x: %.2f, \ty: %.2f, \tz:
%.2f\n",
pVerts[i].x,
pVerts[i].y, pVerts[i].z);
abc(buff);
}
delete[] pVerts;
SkipChunk(fp, Chunk);
}
/***************************************************************************/
/*
*/
/* Well if we have a texture, e.g. coolimage.bmp, then we need to load in
*/
/* our texture coordinates...tu and tv.
*/
/*
*/
/***************************************************************************/
void
ReadMeshTexCoords(FILE *fp, stChunk* Chunk)
{
unsigned short
iNumberVertices = 0;
Chunk->bytesRead += fread(&iNumberVertices, 1, 2, fp);
// e.g. 8 Vertices make up our simple box!
char buff[300];
sprintf(buff, "Number of Vertices %d\n", iNumberVertices);
abc(buff);
// Allocate Memory and dump our texture for each
vertice to the screen.
struct stTex{ float
tu, tv; };
stTex *pTex = new stTex[iNumberVertices];
Chunk->bytesRead += fread( (void*)pTex, 1,
iNumberVertices*sizeof(stTex), fp);
for(int i=0;
i<iNumberVertices; i++)
{
sprintf(buff, "\t Tex Coord: tu: %.2f, \t tv: %.2f\n",
pTex[i].tu,
pTex[i].tv);
abc(buff);
}
delete[] pTex;
SkipChunk(fp, Chunk);
}
/***************************************************************************/
/*
*/
/* Read in our objects name...as each object in our 3D world has a name,
*/
/* for example Box1, HillMesh...whatever you called your object or
object's*/
/* in 3d max before you saved it.
*/
/*
*/
/***************************************************************************/
void
GetMeshObjectName(FILE *fp, stChunk* Chunk)
{
abc("\n");
// The strange thing is, the next few parts of
this chunk represent
// the name of the object. Then we start chunking
again.
unsigned int
characterlen = GetString(fp);
Chunk->bytesRead += characterlen;
ParseChunk(fp, Chunk);
}
// Read in our texture's file name (e.g. coolpic.jpg)
void
GetTexFileName(FILE* fp, stChunk* Chunk)
{
Chunk->bytesRead += GetString(fp);
}
// Read in our diffuse colour (rgb)
void
GetDiffuseColour(FILE *fp, stChunk* Chunk)
{
abc("\n");
struct stRGB{
unsigned char r, g, b; };
stRGB DiffColour;
char ChunkHeader[6];
Chunk->bytesRead += fread(ChunkHeader, 1, 6, fp);
Chunk->bytesRead += fread(&DiffColour, 1, 3, fp);
// e.g. Display our diffuse colour we read in
char buff[300];
sprintf(buff, "Diffuse Colour\t r: %x g: %x b: %x\n",
DiffColour.r, DiffColour.g,
DiffColour.b);
abc(buff);
SkipChunk(fp, Chunk);
}
// Get the materials name, e.g. default-2- etc
void
GetMaterialName(FILE *fp, stChunk* Chunk)
{
Chunk->bytesRead += GetString(fp);
}
/***************************************************************************/
/*
*/
/* If theres a nested sub-chunk, and we know its ID, e.g 0xA000 etc, then
*/
/* we can simply add its ID to the switch list, and add a calling sub
*/
/* functino which will deal with it. Else just skip over that Chunk...
*/
/* and carry on parsing the rest of our file.
*/
/*
*/
/***************************************************************************/
void
ParseChunk(FILE *fp, stChunk* Chunk)
{
abc("\n");
while(Chunk->bytesRead < Chunk->length)
{
stChunk tempChunk = {0};
ReadChunk(fp, &tempChunk);
DisplayChunkInfo(&tempChunk);
switch( tempChunk.ID)
{
// HEADER OUR ENTRY POINT
case EDIT3DS:
ParseChunk(fp, &tempChunk);
break;
// MATERIALS
case MATERIAL:
//0xAFFF
ParseChunk(fp, &tempChunk);
break;
case MAT_NAME:
//0xA000 - sz for hte material name "e.g. default
2"
GetMaterialName(fp, &tempChunk);
break;
case MAT_DIFFUSE:
// Diffuse Colour //0xA020
GetDiffuseColour(fp, &tempChunk);
break;
case MAT_TEXMAP:
//0xA200 - if there's a texture wrapped to it
where here
ParseChunk(fp, &tempChunk);
break;
case MAT_TEXFLNM:
// 0xA300 - get filename of the material
GetTexFileName(fp, &tempChunk);
break;
// OBJECT - MESH'S
case NAMED_OBJECT:
//0x4000
GetMeshObjectName(fp, &tempChunk);
break;
case OBJ_MESH:
//0x4100
ParseChunk(fp, &tempChunk);
break;
case MESH_VERTICES:
//0x4110
ReadMeshVertices(fp, &tempChunk);
break;
case MESH_FACES:
//0x4120
ReadMeshFaces(fp, &tempChunk);
break;
case MESH_TEX_VERT:
//0x4140
ReadMeshTexCoords(fp, &tempChunk);
break;
case MESH_MATER:
//0x4130
ReadMeshMaterials(fp, &tempChunk);
break;
default:
SkipChunk(fp, &tempChunk);
}
Chunk->bytesRead += tempChunk.length;
}
}
/***************************************************************************/
/*
*/
/* Our 3DS File Reader Entry Point - Lets read that baby in and show it
*/
/*
who's boss".
*/
/*
*/
/***************************************************************************/
void
read3ds()
{
FILE* pFile;
pFile = fopen(FILENAME, "rb");
stChunk Chunk = {0};
ReadChunk(pFile, &Chunk);
ParseChunk( pFile, &Chunk );
fclose(pFile);
}
/***************************************************************************/
/*
*/
/* The program entry point, this is where we start and end.
*/
/*
*/
/***************************************************************************/
int
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR,
int)
{
read3ds();
return 0;
} |