Skip to content

Instantly share code, notes, and snippets.

@iondune
Created April 20, 2014 23:29
Show Gist options
  • Save iondune/11127973 to your computer and use it in GitHub Desktop.
Save iondune/11127973 to your computer and use it in GitHub Desktop.
#include <vector>
#include <string>
#include <iostream>
#include <map>
#include <sys/stat.h>
#include "glm/glm.hpp"
class SVertex
{
public:
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TextureCoordinates;
glm::vec3 Color;
};
class SMaterial
{
public:
glm::vec3 AmbientColor, DiffuseColor, SpecularColor;
float Shininess;
};
class CMesh
{
public:
struct STriangle
{
unsigned int Indices[3];
glm::vec3 Normal;
};
struct SMeshBuffer
{
std::vector<SVertex> Vertices;
std::vector<STriangle> Triangles;
void updateBuffers();
void writeObjMesh(std::string const & fileName);
SMaterial Material;
};
std::vector<SMeshBuffer *> MeshBuffers;
};
static long filelength(int f)
{
struct stat buf;
fstat(f, &buf);
return(buf.st_size);
}
CMesh * const load3dsMesh(std::string const & fileName)
{
int i; //Index variable
FILE *l_file; //File pointer
unsigned short l_chunk_id; //Chunk identifier
unsigned int l_chunk_lenght; //Chunk lenght
unsigned char l_char; //Char variable
unsigned short l_qty; //Number of elements in each chunk
unsigned short l_face_flags; //Flag that stores some face information
if ((l_file=fopen (fileName.c_str(), "rb"))== NULL)
{
std::cerr << "Failed to open 3ds mesh file: '" << fileName << "'." << std::endl;
return 0; //Open the file
}
CMesh * MeshWrapper = new CMesh();
CMesh::SMeshBuffer * Mesh = new CMesh::SMeshBuffer();
std::map<std::string, glm::vec3> Materials;
std::map<CMesh::SMeshBuffer *, std::string> FaceMaterials;
std::string currentMat;
int bufferCount = 0;
while (ftell (l_file) < filelength (fileno (l_file))) //Loop to scan the whole file
//while(!EOF)
{
//getch(); //Insert this command for debug (to wait for keypress for each chuck reading)
fread (&l_chunk_id, 2, 1, l_file); //Read the chunk header
//printf("ChunkID: %x\n",l_chunk_id);
fread (&l_chunk_lenght, 4, 1, l_file); //Read the lenght of the chunk
//printf("ChunkLenght: %x\n",l_chunk_lenght);
switch (l_chunk_id)
{
//----------------- MAIN3DS -----------------
// Description: Main chunk, contains all the other chunks
// Chunk ID: 4d4d
// Chunk Lenght: 0 + sub chunks
//-------------------------------------------
case 0x4d4d:
break;
//----------------- EDIT3DS -----------------
// Description: 3D Editor chunk, objects layout info
// Chunk ID: 3d3d (hex)
// Chunk Lenght: 0 + sub chunks
//-------------------------------------------
case 0x3d3d:
break;
//--------------- EDIT_OBJECT ---------------
// Description: Object block, info for each object
// Chunk ID: 4000 (hex)
// Chunk Lenght: len(object name) + sub chunks
//-------------------------------------------
case 0x4000:
i=0;
do
{
fread (&l_char, 1, 1, l_file);
//p_object->name[i]=l_char; // Throw out name - why do we care? we don't! bwahahahaha
i++;
} while(l_char != '\0' && i < 20);
break;
//--------------- OBJ_TRIMESH ---------------
// Description: Triangular mesh, contains chunks for 3d mesh info
// Chunk ID: 4100 (hex)
// Chunk Lenght: 0 + sub chunks
//-------------------------------------------
case 0x4100:
break;
//--------------- TRI_VERTEXL ---------------
// Description: Vertices list
// Chunk ID: 4110 (hex)
// Chunk Lenght: 1 x unsigned short (number of vertices)
// + 3 x float (vertex coordinates) x (number of vertices)
// + sub chunks
//-------------------------------------------
case 0x4110:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
if (bufferCount)
{
MeshWrapper->MeshBuffers.push_back(Mesh);
Mesh = new CMesh::SMeshBuffer();
}
Mesh->Vertices.resize(l_qty);
bufferCount++;
//printf("Number of vertices: %d\n",l_qty);
for (i=0; i<l_qty; i++)
{
fread (& Mesh->Vertices[i].Position.x, sizeof(float), 1, l_file);
//printf("Vertices list x: %f\n",Mesh->Vertices[i].Position.x);
fread (& Mesh->Vertices[i].Position.z, sizeof(float), 1, l_file);
//printf("Vertices list y: %f\n",Mesh->Vertices[i].Position.y);
fread (& Mesh->Vertices[i].Position.y, sizeof(float), 1, l_file);
//printf("Vertices list z: %f\n",Mesh->Vertices[i].Position.z);
}
break;
//--------------- TRI_FACEL1 ----------------
// Description: Polygons (faces) list
// Chunk ID: 4120 (hex)
// Chunk Lenght: 1 x unsigned short (number of polygons)
// + 3 x unsigned short (polygon points) x (number of polygons)
// + sub chunks
//-------------------------------------------
case 0x4120:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
Mesh->Triangles.resize(l_qty);
//printf("Number of polygons: %d\n",l_qty);
for (i=0; i<l_qty; i++)
{
Mesh->Triangles[i].Indices[0] = 0;
Mesh->Triangles[i].Indices[1] = 0;
Mesh->Triangles[i].Indices[2] = 0;
fread (& Mesh->Triangles[i].Indices[0], sizeof (unsigned short), 1, l_file);
//printf("Polygon point a: %d\n", Mesh->Triangles[i].Indices[0]);
fread (& Mesh->Triangles[i].Indices[1], sizeof (unsigned short), 1, l_file);
//printf("Polygon point b: %d\n", Mesh->Triangles[i].Indices[1]);
fread (& Mesh->Triangles[i].Indices[2], sizeof (unsigned short), 1, l_file);
//printf("Polygon point c: %d\n", Mesh->Triangles[i].Indices[2]);
fread (&l_face_flags, sizeof (unsigned short), 1, l_file);
//printf("Face flags: %x\n",l_face_flags);
}
break;
//------------- TRI_MAPPINGCOORS ------------
// Description: Vertices list
// Chunk ID: 4140 (hex)
// Chunk Lenght: 1 x unsigned short (number of mapping points)
// + 2 x float (mapping coordinates) x (number of mapping points)
// + sub chunks
//-------------------------------------------
case 0x4140:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
for (i=0; i<l_qty; i++)
{
fread (& Mesh->Vertices[i].TextureCoordinates[0], sizeof (float), 1, l_file);
//printf("Mapping list u: %f\n", Mesh->Vertices[i].TextureCoordinates[0]);
fread (& Mesh->Vertices[i].TextureCoordinates[1], sizeof (float), 1, l_file);
//printf("Mapping list v: %f\n", Mesh->Vertices[i].TextureCoordinates[1]);
}
break;
case 0xAFFF:
{
//printf("found material block in %s (%d)!\n", fileName.c_str(), l_chunk_lenght);
//fseek(l_file, l_chunk_lenght-6, SEEK_CUR);
break;
}
case 0x4130:
{
//printf("found faces material block in %s (%d)!\n", fileName.c_str(), l_chunk_lenght);
i=0;
char name[20];
do
{
fread (&l_char, 1, 1, l_file);
name[i]=l_char;
i++;
} while(l_char != '\0' && i < 20);
FaceMaterials[Mesh] = name;
fseek(l_file, l_chunk_lenght - i - 6, SEEK_CUR);
break;
}
case 0xA000:
{
//printf("found material name in %s (%d)!\n", fileName.c_str(), l_chunk_lenght);
i=0;
char name[20];
do
{
fread (&l_char, 1, 1, l_file);
name[i]=l_char;
i++;
} while(l_char != '\0' && i < 20);
currentMat = name;
fseek(l_file, l_chunk_lenght - i - 6, SEEK_CUR);
break;
}
case 0xA010:
{
//printf("found ambient block in %s (%d)!\n", fileName.c_str(), l_chunk_lenght);
fseek(l_file, l_chunk_lenght-6, SEEK_CUR);
break;
}
case 0xA020:
{
//printf("found diffuse block in %s (%d)!\n", fileName.c_str(), l_chunk_lenght);
unsigned char what[1000];
fread(what, 1, l_chunk_lenght-6, l_file);
if (l_chunk_lenght == 15)
{
Materials[currentMat].x = what[6] / 256.f;
Materials[currentMat].y = what[7] / 256.f;
Materials[currentMat].z = what[8] / 256.f;
}
else if (l_chunk_lenght == 24)
{
Materials[currentMat].x = (*(float *)& what[6]);// (float) (std::numeric_limits<unsigned short>::max());
Materials[currentMat].y = (*(float *)& what[10]);// (float) (std::numeric_limits<unsigned short>::max());
Materials[currentMat].z = (*(float *)& what[14]);// (float) (std::numeric_limits<unsigned short>::max());
}
//fseek(l_file, l_chunk_lenght-6, SEEK_CUR);
break;
}
case 0xA030:
{
//printf("found diffuse block in %s (%d)!\n", fileName.c_str(), l_chunk_lenght);
fseek(l_file, l_chunk_lenght-6, SEEK_CUR);
break;
}
case 0xA040:
{
//printf("found specular block in %s (%d)!\n", fileName.c_str(), l_chunk_lenght);
fseek(l_file, l_chunk_lenght-6, SEEK_CUR);
break;
}
//----------- Skip unknow chunks ------------
//We need to skip all the chunks that currently we don't use
//We use the chunk lenght information to set the file pointer
//to the same level next chunk
//-------------------------------------------
default:
fseek(l_file, l_chunk_lenght-6, SEEK_CUR);
}
}
fclose (l_file);
for (std::map<CMesh::SMeshBuffer *, std::string>::iterator it = FaceMaterials.begin(); it != FaceMaterials.end(); ++ it)
it->first->Material.DiffuseColor = Materials[it->second];
MeshWrapper->MeshBuffers.push_back(Mesh);
return MeshWrapper;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment