finished material and mesh serialisation, added model class
This commit is contained in:
parent
116a5e3d1a
commit
66784724d8
198
src/mesh.cpp
198
src/mesh.cpp
@ -78,7 +78,7 @@ void Mesh::initGL()
|
|||||||
{
|
{
|
||||||
auto posBuffer = new TBuffer<glm::vec3>(positions3D, Buffer::VBO);
|
auto posBuffer = new TBuffer<glm::vec3>(positions3D, Buffer::VBO);
|
||||||
posBuffer->setVertexAttrib(0, 3);
|
posBuffer->setVertexAttrib(0, 3);
|
||||||
addBuffer(posBuffer, POSITION_BUFFER);
|
addBuffer(posBuffer, POSITION3D_BUFFER);
|
||||||
|
|
||||||
// init normals vbo
|
// init normals vbo
|
||||||
if(!normals.empty())
|
if(!normals.empty())
|
||||||
@ -100,7 +100,7 @@ void Mesh::initGL()
|
|||||||
{
|
{
|
||||||
auto posBuffer = new TBuffer<glm::vec2>(positions2D, Buffer::VBO);
|
auto posBuffer = new TBuffer<glm::vec2>(positions2D, Buffer::VBO);
|
||||||
posBuffer->setVertexAttrib(0, 2);
|
posBuffer->setVertexAttrib(0, 2);
|
||||||
addBuffer(posBuffer, POSITION_BUFFER);
|
addBuffer(posBuffer, POSITION2D_BUFFER);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -184,22 +184,33 @@ void Mesh::destroyGL()
|
|||||||
clearBuffers();
|
clearBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mesh::clearData()
|
||||||
|
{
|
||||||
|
positions3D.clear();
|
||||||
|
normals.clear();
|
||||||
|
tangents.clear();
|
||||||
|
positions2D.clear();
|
||||||
|
texCoords.clear();
|
||||||
|
instances_offsets.clear();
|
||||||
|
indices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int Mesh::getFlags()
|
unsigned int Mesh::getFlags()
|
||||||
{
|
{
|
||||||
unsigned int flags = material->getFlags();
|
unsigned int flags = material->getFlags();
|
||||||
|
|
||||||
if(!indices.empty())
|
if(!(indices.empty() || buffersId[INDICES_BUFFER] == -1))
|
||||||
flags |= 1 << MESH_INDEXED;
|
flags |= 1 << MESH_INDEXED;
|
||||||
if(!texCoords.empty())
|
if(!(texCoords.empty() || buffersId[TEXCOORD_BUFFER] == -1))
|
||||||
flags |= 1 << MESH_TEXTURABLE;
|
flags |= 1 << MESH_TEXTURABLE;
|
||||||
if(!instances_offsets.empty())
|
if(!(instances_offsets.empty() || buffersId[INSTANCE_BUFFER] == -1))
|
||||||
flags |= 1 << MESH_INSTANCED;
|
flags |= 1 << MESH_INSTANCED;
|
||||||
|
|
||||||
if(!positions3D.empty())
|
if(!(positions3D.empty() || buffersId[POSITION3D_BUFFER] == -1))
|
||||||
{
|
{
|
||||||
flags |= 1 << MESH_3D;
|
flags |= 1 << MESH_3D;
|
||||||
|
|
||||||
if(!tangents.empty())
|
if((!tangents.empty() || buffersId[TANGENT_BUFFER] == -1))
|
||||||
flags |= 1 << MESH_TANGENT_SPACE;
|
flags |= 1 << MESH_TANGENT_SPACE;
|
||||||
if(isDoubleSided)
|
if(isDoubleSided)
|
||||||
flags |= 1 << MESH_DOUBLE_SIDED;
|
flags |= 1 << MESH_DOUBLE_SIDED;
|
||||||
@ -399,3 +410,176 @@ void Mesh::computeBoundingBox(glm::vec3 &min, glm::vec3 &max)
|
|||||||
max.z = pos.z;
|
max.z = pos.z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// serialisation methods
|
||||||
|
|
||||||
|
struct MeshHeader
|
||||||
|
{
|
||||||
|
unsigned int flags;
|
||||||
|
int nbPositions;
|
||||||
|
int depth;
|
||||||
|
int nbInstances_offsets;
|
||||||
|
int nbIndices;
|
||||||
|
int nameLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool writeBuffer(const std::vector<T> &vec, std::FILE *file)
|
||||||
|
{
|
||||||
|
size_t nbWritten = std::fwrite(vec.data(), sizeof(T), vec.size(), file);
|
||||||
|
return (nbWritten == vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool readBuffer(std::vector<T> &vec, std::FILE *file)
|
||||||
|
{
|
||||||
|
size_t nbRead = std::fread(vec.data(), sizeof(T), vec.size(), file);
|
||||||
|
return (nbRead == vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mesh::serialize(Mesh* mesh, FILE *file)
|
||||||
|
{
|
||||||
|
// creating header
|
||||||
|
MeshHeader header;
|
||||||
|
header.flags = mesh->getFlags();
|
||||||
|
if(header.flags & (1 << Mesh::MESH_3D))
|
||||||
|
header.nbPositions = mesh->positions3D.size();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
header.nbPositions = mesh->positions2D.size();
|
||||||
|
header.depth = mesh->getDepth();
|
||||||
|
}
|
||||||
|
header.nbIndices = mesh->indices.size();
|
||||||
|
header.nbInstances_offsets = mesh->instances_offsets.size();
|
||||||
|
header.nameLength = mesh->getName().size();
|
||||||
|
|
||||||
|
if(header.nbPositions == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// writing header
|
||||||
|
size_t nbWritten;
|
||||||
|
|
||||||
|
nbWritten = std::fwrite(&header, sizeof(MeshHeader), 1, file);
|
||||||
|
if(nbWritten != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(header.nameLength != 0)
|
||||||
|
{
|
||||||
|
nbWritten = std::fwrite(mesh->getName().data(), header.nameLength, 1, file);
|
||||||
|
if(nbWritten != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// writing buffers
|
||||||
|
if(header.flags & (1 << Mesh::MESH_3D))
|
||||||
|
{
|
||||||
|
if(!writeBuffer(mesh->positions3D, file))
|
||||||
|
return false;
|
||||||
|
if(mesh->normals.size() == 0)
|
||||||
|
mesh->computeNormals();
|
||||||
|
if(!writeBuffer(mesh->normals, file))
|
||||||
|
return false;
|
||||||
|
if(header.flags & (1 << Mesh::MESH_TANGENT_SPACE))
|
||||||
|
{
|
||||||
|
if(!writeBuffer(mesh->tangents, file))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!writeBuffer(mesh->positions2D, file))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header.nbInstances_offsets)
|
||||||
|
{
|
||||||
|
if(!writeBuffer(mesh->instances_offsets, file))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header.nbIndices)
|
||||||
|
{
|
||||||
|
if(!writeBuffer(mesh->indices, file))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header.flags & (1 << Mesh::MESH_TEXTURABLE))
|
||||||
|
{
|
||||||
|
if(!writeBuffer(mesh->texCoords, file))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh* Mesh::deserialize(FILE *file)
|
||||||
|
{
|
||||||
|
MeshHeader header;
|
||||||
|
size_t nbRead = std::fread(&header, sizeof(MeshHeader), 1, file);
|
||||||
|
|
||||||
|
// deserializing mesh
|
||||||
|
Mesh *mesh = NULL;
|
||||||
|
if(nbRead == 1 && header.nbPositions != 0)
|
||||||
|
mesh = new Mesh();
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
std::string name = "mesh";
|
||||||
|
if(header.nameLength != 0)
|
||||||
|
{
|
||||||
|
name.resize(header.nameLength);
|
||||||
|
if(!fread(&(name[0]), header.nameLength, 1, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
}
|
||||||
|
mesh->setName(name);
|
||||||
|
|
||||||
|
if(header.flags & (1 << Mesh::MESH_3D))
|
||||||
|
{
|
||||||
|
mesh->positions3D.reserve(header.nbPositions);
|
||||||
|
if(!readBuffer(mesh->positions3D, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
mesh->normals.reserve(header.nbPositions);
|
||||||
|
if(!readBuffer(mesh->normals, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
if(header.flags & (1 << Mesh::MESH_TANGENT_SPACE))
|
||||||
|
{
|
||||||
|
mesh->tangents.reserve(header.nbPositions);
|
||||||
|
if(!readBuffer(mesh->tangents, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mesh->positions2D.reserve(header.nbPositions);
|
||||||
|
if(!readBuffer(mesh->positions2D, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
mesh->setDepth(header.depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header.nbInstances_offsets)
|
||||||
|
{
|
||||||
|
mesh->instances_offsets.reserve(header.nbInstances_offsets);
|
||||||
|
if(!readBuffer(mesh->instances_offsets, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header.nbIndices)
|
||||||
|
{
|
||||||
|
mesh->indices.reserve(header.nbIndices);
|
||||||
|
if(!readBuffer(mesh->indices, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header.flags & (1 << Mesh::MESH_TEXTURABLE))
|
||||||
|
{
|
||||||
|
mesh->texCoords.reserve(header.nbPositions);
|
||||||
|
if(!readBuffer(mesh->texCoords, file))
|
||||||
|
{ delete(mesh); return NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh->setIsBillboard(header.flags & (1 << Mesh::MESH_BILLBOARD));
|
||||||
|
mesh->setIsDoubleSided(header.flags & (1 << Mesh::MESH_DOUBLE_SIDED));
|
||||||
|
mesh->setIsShadowCaster(header.flags & (1 << Mesh::MESH_SHADOWED));
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
26
src/mesh.h
26
src/mesh.h
@ -102,6 +102,11 @@ public:
|
|||||||
void initGL();
|
void initGL();
|
||||||
void draw(Shader* shader, bool drawNormals = true, bool drawTexCoord = true, bool drawTangents = true);
|
void draw(Shader* shader, bool drawNormals = true, bool drawTexCoord = true, bool drawTangents = true);
|
||||||
void destroyGL();
|
void destroyGL();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief clearData clears all data vectors, but keeps GPU data allocated.
|
||||||
|
*/
|
||||||
|
void clearData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief getFlags returns the flags that defines the specificities of the mesh and his material
|
* @brief getFlags returns the flags that defines the specificities of the mesh and his material
|
||||||
@ -197,6 +202,24 @@ public:
|
|||||||
*/
|
*/
|
||||||
void computeBoundingBox(glm::vec3 &min, glm::vec3 &max);
|
void computeBoundingBox(glm::vec3 &min, glm::vec3 &max);
|
||||||
|
|
||||||
|
/*************************************************************/
|
||||||
|
/* SERIALISATION */
|
||||||
|
/*************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief serializeMesh can be used to save a mesh
|
||||||
|
* @return true if the mesh has succesfully been saved
|
||||||
|
*/
|
||||||
|
static bool serialize(Mesh* mesh, FILE *file);
|
||||||
|
|
||||||
|
bool serialize(FILE *file) { return serialize(this, file); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deserializeMesh can be used to load a mesh
|
||||||
|
* @return the loaded mesh of NULL if a reading error has occured
|
||||||
|
*/
|
||||||
|
static Mesh* deserialize(FILE *file);
|
||||||
|
|
||||||
/*************************************************************/
|
/*************************************************************/
|
||||||
/* ADVANCED CUSTOMISATION */
|
/* ADVANCED CUSTOMISATION */
|
||||||
/*************************************************************/
|
/*************************************************************/
|
||||||
@ -224,7 +247,8 @@ protected:
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
// required buffer
|
// required buffer
|
||||||
POSITION_BUFFER,
|
POSITION2D_BUFFER,
|
||||||
|
POSITION3D_BUFFER,
|
||||||
|
|
||||||
// indices buffers
|
// indices buffers
|
||||||
INDICES_BUFFER,
|
INDICES_BUFFER,
|
||||||
|
116
src/model.cpp
Normal file
116
src/model.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include "model.h"
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "texture.h"
|
||||||
|
#include "phongmaterial.h"
|
||||||
|
|
||||||
|
Model::~Model()
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
destroyGL();
|
||||||
|
for(Mesh *m : m_meshes)
|
||||||
|
delete m;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image* Model::getImage(const std::string &name)
|
||||||
|
{
|
||||||
|
for(TextureImg &tex : m_textures)
|
||||||
|
{
|
||||||
|
if(name.compare(tex.name) == 0)
|
||||||
|
return tex.img;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture* Model::getTexture(const std::string &name)
|
||||||
|
{
|
||||||
|
for(TextureImg &tex : m_textures)
|
||||||
|
{
|
||||||
|
if(name.compare(tex.name) == 0)
|
||||||
|
return tex.tex;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::destroy()
|
||||||
|
{
|
||||||
|
for(Mesh* m : m_meshes)
|
||||||
|
m->clearData();
|
||||||
|
for(TextureImg &tex : m_textures)
|
||||||
|
{
|
||||||
|
delete tex.img;
|
||||||
|
tex.img = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::initGL()
|
||||||
|
{
|
||||||
|
for(Mesh* m : m_meshes)
|
||||||
|
m->initGL();
|
||||||
|
for(TextureImg &tex : m_textures)
|
||||||
|
{
|
||||||
|
if(tex.tex == NULL)
|
||||||
|
tex.tex = new Texture(tex.img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::destroyGL()
|
||||||
|
{
|
||||||
|
for(Mesh* m : m_meshes)
|
||||||
|
m->destroyGL();
|
||||||
|
for(TextureImg &tex : m_textures)
|
||||||
|
{
|
||||||
|
if(tex.tex != NULL)
|
||||||
|
{
|
||||||
|
delete tex.tex;
|
||||||
|
tex.tex = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Model::save(const std::string &filename, const std::string &texturesPath)
|
||||||
|
{
|
||||||
|
// open file
|
||||||
|
std::FILE *file = std::fopen(filename.c_str(), "w");
|
||||||
|
if(file == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
int size = m_meshes.size();
|
||||||
|
if(std::fwrite(&size, sizeof(int), 1, file))
|
||||||
|
{
|
||||||
|
ok = true;
|
||||||
|
for(Mesh* m : m_meshes)
|
||||||
|
{
|
||||||
|
ok = ok && m->serialize(file);
|
||||||
|
PhongMaterial* mat = (PhongMaterial*)m->getMaterial();
|
||||||
|
ok = ok && mat->serialize(file);
|
||||||
|
}
|
||||||
|
for(Model::TextureImg &texImg : m_textures)
|
||||||
|
{
|
||||||
|
std::string texFilename = texturesPath + texImg.name + ".png";
|
||||||
|
if(texImg.img == NULL && texImg.tex != NULL)
|
||||||
|
texImg.img = texImg.tex->getData();
|
||||||
|
if(texImg.img != NULL)
|
||||||
|
ok = ok && texImg.img->save(texFilename);
|
||||||
|
}
|
||||||
|
std::fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// finishing
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* Model::load(const std::string &filename, const std::string &texturesPath)
|
||||||
|
{
|
||||||
|
// open file
|
||||||
|
std::FILE *file = std::fopen(filename.c_str(), "r");
|
||||||
|
if(file == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
|
||||||
|
// finishing
|
||||||
|
return NULL;
|
||||||
|
}
|
90
src/model.h
Normal file
90
src/model.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#ifndef MODEL_H
|
||||||
|
#define MODEL_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Mesh;
|
||||||
|
class Image;
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
class Model
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
struct TextureImg
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
Texture* tex;
|
||||||
|
Image* img;
|
||||||
|
|
||||||
|
TextureImg(const std::string n, Image* i) :
|
||||||
|
name(n), tex(NULL), img(i) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Mesh*> m_meshes;
|
||||||
|
std::vector<TextureImg> m_textures;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~Model();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief addMesh adds a mesh to the mesh list
|
||||||
|
*/
|
||||||
|
void addMesh(Mesh *mesh) { m_meshes.push_back(mesh); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief addImage adds an image to the texture pack
|
||||||
|
*/
|
||||||
|
void addImage(const std::string &name, Image* img)
|
||||||
|
{
|
||||||
|
m_textures.push_back(TextureImg(name, img));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getMeshes returns the mesh array
|
||||||
|
*/
|
||||||
|
const std::vector<Mesh*>& getMeshes() { return m_meshes; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getImage returns the image which has the specified name, or NULL if there are no images of this name.
|
||||||
|
*/
|
||||||
|
Image* getImage(const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getTexture returns the texture which has the specified name, or NULL if there are no images of this name.
|
||||||
|
*/
|
||||||
|
Texture* getTexture(const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief destroy frees Mesh and Image memory in the RAM, but it stays allocated in GPU memory.
|
||||||
|
*/
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief initGL uploads image and mesh data to GPU memory
|
||||||
|
*/
|
||||||
|
void initGL();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief destroyGL frees the meshes and the textures from GPU memory
|
||||||
|
*/
|
||||||
|
void destroyGL();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief save saves the model on a file
|
||||||
|
* @param filename is the name of the resulting file
|
||||||
|
* @param texturesPath is the existing folder where the textures will be saved
|
||||||
|
* @return true if the save succeeded
|
||||||
|
*/
|
||||||
|
bool save(const std::string &filename, const std::string &texturesPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief load loads the model from a file
|
||||||
|
* @param filename is the name of the target file
|
||||||
|
* @param texturesPath is the existing folder where the textures will be gathered
|
||||||
|
* @return the model if the loading succeeded, or NULL if it failed
|
||||||
|
*/
|
||||||
|
static Model* load(const std::string &filename, const std::string &texturesPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MODEL_H
|
@ -64,3 +64,76 @@ unsigned int PhongMaterial::getFlags()
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// serialisation methods :
|
||||||
|
|
||||||
|
struct MaterialHeader
|
||||||
|
{
|
||||||
|
glm::vec3 emission;
|
||||||
|
glm::vec3 diffuse;
|
||||||
|
glm::vec3 specular;
|
||||||
|
float shininess;
|
||||||
|
int textureLengths[PhongMaterial::NB_PHONG_SLOTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool PhongMaterial::serialize(PhongMaterial* mat, FILE *file)
|
||||||
|
{
|
||||||
|
unsigned int flags = mat->getFlags();
|
||||||
|
|
||||||
|
if(!fwrite(&flags, sizeof(unsigned int), 1, file))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(flags & (1 << Mesh::MATERIAL_PHONG))
|
||||||
|
{
|
||||||
|
MaterialHeader header;
|
||||||
|
header.emission = mat->emission;
|
||||||
|
header.diffuse = mat->diffuse;
|
||||||
|
header.specular = mat->specular;
|
||||||
|
header.shininess = mat->shininess;
|
||||||
|
|
||||||
|
for(int i=0; i<PhongMaterial::NB_PHONG_SLOTS; ++i)
|
||||||
|
{
|
||||||
|
if(mat->textures[i] != NULL)
|
||||||
|
header.textureLengths[i] = mat->textureNames[i].length()+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!std::fwrite(&header, sizeof(MaterialHeader), 1, file))
|
||||||
|
return false;
|
||||||
|
for(int i=0; i<PhongMaterial::NB_PHONG_SLOTS; ++i)
|
||||||
|
{
|
||||||
|
if(header.textureLengths[i] > 0)
|
||||||
|
{
|
||||||
|
if(!std::fwrite(mat->textureNames[i].c_str(), header.textureLengths[i], 1, file))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhongMaterial* PhongMaterial::deserialize(FILE *file)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
if(!std::fread(&flags, sizeof(int), 1, file))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
MaterialHeader header;
|
||||||
|
if(!std::fread(&header, sizeof(MaterialHeader), 1, file))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
PhongMaterial *mat = new PhongMaterial();
|
||||||
|
|
||||||
|
mat->diffuse = header.diffuse;
|
||||||
|
mat->emission = header.emission;
|
||||||
|
mat->specular = header.specular;
|
||||||
|
mat->shininess = header.shininess;
|
||||||
|
for(int i=0; i<PhongMaterial::NB_PHONG_SLOTS; ++i)
|
||||||
|
{
|
||||||
|
char str[256];
|
||||||
|
if(!std::fread(str, header.textureLengths[i], 1, file))
|
||||||
|
{ delete mat; return NULL; }
|
||||||
|
mat->textureNames[i] = std::string(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
@ -44,6 +44,21 @@ struct PhongMaterial : public Material
|
|||||||
virtual void bindAttributes(Shader* myShader);
|
virtual void bindAttributes(Shader* myShader);
|
||||||
|
|
||||||
virtual unsigned int getFlags();
|
virtual unsigned int getFlags();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief serializeMaterial saves a material to a file
|
||||||
|
* @return true if the save succeeded
|
||||||
|
*/
|
||||||
|
static bool serialize(PhongMaterial* mat, FILE *file);
|
||||||
|
bool serialize(FILE *file) { return serialize(this, file); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deserializeMaterial creates a material from reading a file,
|
||||||
|
* be careful, this method has no way to load the attached textures, so you must do it manually,
|
||||||
|
* however, you can use the texture names stored in the textureNames array to find which textures are requested.
|
||||||
|
* @return the material or NULL if the loading failed
|
||||||
|
*/
|
||||||
|
static PhongMaterial* deserialize(FILE *file);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PHONGMATERIAL_H
|
#endif // PHONGMATERIAL_H
|
||||||
|
@ -1,291 +0,0 @@
|
|||||||
#include "serializers.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include "mesh.h"
|
|
||||||
#include "light.h"
|
|
||||||
#include "texture.h"
|
|
||||||
#include "phongmaterial.h"
|
|
||||||
|
|
||||||
namespace serializers
|
|
||||||
{
|
|
||||||
|
|
||||||
// STRUCTS
|
|
||||||
|
|
||||||
struct MeshHeader
|
|
||||||
{
|
|
||||||
unsigned int flags;
|
|
||||||
int nbPositions;
|
|
||||||
int depth;
|
|
||||||
int nbInstances_offsets;
|
|
||||||
int nbIndices;
|
|
||||||
int nameLength;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MaterialHeader
|
|
||||||
{
|
|
||||||
glm::vec3 emission;
|
|
||||||
glm::vec3 diffuse;
|
|
||||||
glm::vec3 specular;
|
|
||||||
float shininess;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LightHeader
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// PRIVATE FUNCTIONS
|
|
||||||
|
|
||||||
bool serializeMesh(Mesh* mesh, const MeshHeader &header, FILE *file);
|
|
||||||
|
|
||||||
bool deserializeMesh(Mesh* mesh, const MeshHeader &header, FILE *file);
|
|
||||||
|
|
||||||
bool serializeMaterial(Material* material, FILE *file);
|
|
||||||
|
|
||||||
Material* deserializeMaterial(FILE *file);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool writeBuffer(const std::vector<T> &vec, std::FILE *file);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool readBuffer(std::vector<T> &vec, std::FILE *file);
|
|
||||||
|
|
||||||
// IMPLEMENTATIONS
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool writeBuffer(const std::vector<T> &vec, std::FILE *file)
|
|
||||||
{
|
|
||||||
size_t nbWritten = std::fwrite(vec.data(), sizeof(T), vec.size(), file);
|
|
||||||
return (nbWritten == vec.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool readBuffer(std::vector<T> &vec, std::FILE *file)
|
|
||||||
{
|
|
||||||
size_t nbRead = std::fread(vec.data(), sizeof(T), vec.size(), file);
|
|
||||||
return (nbRead == vec.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool saveMesh(const std::string &filename, Mesh *mesh)
|
|
||||||
{
|
|
||||||
// open file
|
|
||||||
std::FILE *file = std::fopen(filename.c_str(), "w");
|
|
||||||
if(file == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// creating header
|
|
||||||
MeshHeader header;
|
|
||||||
header.flags = mesh->getFlags();
|
|
||||||
if(header.flags & (1 << Mesh::MESH_3D))
|
|
||||||
header.nbPositions = mesh->positions3D.size();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mesh->positions2D.size();
|
|
||||||
header.depth = mesh->getDepth();
|
|
||||||
}
|
|
||||||
header.nbIndices = mesh->indices.size();
|
|
||||||
header.nbInstances_offsets = mesh->instances_offsets.size();
|
|
||||||
header.nameLength = mesh->getName().size();
|
|
||||||
|
|
||||||
// serializing
|
|
||||||
bool ok = false;
|
|
||||||
if(header.nbPositions != 0)
|
|
||||||
ok = serializeMesh(mesh, header, file);
|
|
||||||
|
|
||||||
// finishing
|
|
||||||
std::fclose(file);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool serializeMesh(Mesh* mesh, const MeshHeader &header, FILE *file)
|
|
||||||
{
|
|
||||||
// writing header
|
|
||||||
size_t nbWritten;
|
|
||||||
|
|
||||||
nbWritten = std::fwrite(&header, sizeof(MeshHeader), 1, file);
|
|
||||||
if(nbWritten != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(header.nameLength != 0)
|
|
||||||
{
|
|
||||||
nbWritten = std::fwrite(mesh->getName().data(), header.nameLength, 1, file);
|
|
||||||
if(nbWritten != 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// writing buffers
|
|
||||||
if(header.flags & (1 << Mesh::MESH_3D))
|
|
||||||
{
|
|
||||||
if(!writeBuffer(mesh->positions3D, file))
|
|
||||||
return false;
|
|
||||||
if(mesh->normals.size() == 0)
|
|
||||||
mesh->computeNormals();
|
|
||||||
if(!writeBuffer(mesh->normals, file))
|
|
||||||
return false;
|
|
||||||
if(header.flags & (1 << Mesh::MESH_TANGENT_SPACE))
|
|
||||||
{
|
|
||||||
if(!writeBuffer(mesh->tangents, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!writeBuffer(mesh->positions2D, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.nbInstances_offsets)
|
|
||||||
{
|
|
||||||
if(!writeBuffer(mesh->instances_offsets, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.nbIndices)
|
|
||||||
{
|
|
||||||
if(!writeBuffer(mesh->indices, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.flags & (1 << Mesh::MESH_TEXTURABLE))
|
|
||||||
{
|
|
||||||
if(!writeBuffer(mesh->texCoords, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool serializeMaterial(Material* material, FILE *file)
|
|
||||||
{
|
|
||||||
unsigned int flags = material->getFlags();
|
|
||||||
|
|
||||||
if(!fwrite(&flags, sizeof(unsigned int), 1, file))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(flags & (1 << Mesh::MATERIAL_PHONG))
|
|
||||||
{
|
|
||||||
MaterialHeader header;
|
|
||||||
PhongMaterial *mat = (PhongMaterial*)material;
|
|
||||||
header.emission = mat->emission;
|
|
||||||
header.diffuse = mat->diffuse;
|
|
||||||
header.specular = mat->specular;
|
|
||||||
header.shininess = mat->shininess;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool saveLight(const std::string &filename, Light *light)
|
|
||||||
{
|
|
||||||
std::FILE *file = std::fopen(filename.c_str(), "w");
|
|
||||||
if(file == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::fclose(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh* loadMesh(const std::string &filename)
|
|
||||||
{
|
|
||||||
// open file
|
|
||||||
std::FILE *file = std::fopen(filename.c_str(), "r");
|
|
||||||
if(file == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// reading header
|
|
||||||
MeshHeader header;
|
|
||||||
size_t nbRead = std::fread(&header, sizeof(MeshHeader), 1, file);
|
|
||||||
|
|
||||||
// deserializing mesh
|
|
||||||
bool ok = false;
|
|
||||||
Mesh *mesh = NULL;
|
|
||||||
if(nbRead == 1 && header.nbPositions != 0)
|
|
||||||
{
|
|
||||||
mesh = new Mesh();
|
|
||||||
ok = deserializeMesh(mesh, header, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// finishing
|
|
||||||
std::fclose(file);
|
|
||||||
|
|
||||||
if(!ok && mesh != NULL)
|
|
||||||
{
|
|
||||||
delete mesh;
|
|
||||||
mesh = NULL;
|
|
||||||
}
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool deserializeMesh(Mesh* mesh, const MeshHeader &header, FILE *file)
|
|
||||||
{
|
|
||||||
std::string name = "mesh";
|
|
||||||
if(header.nameLength != 0)
|
|
||||||
{
|
|
||||||
name.resize(header.nameLength);
|
|
||||||
if(!fread(&(name[0]), header.nameLength, 1, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mesh->setName(name);
|
|
||||||
|
|
||||||
if(header.flags & (1 << Mesh::MESH_3D))
|
|
||||||
{
|
|
||||||
mesh->positions3D.reserve(header.nbPositions);
|
|
||||||
if(!readBuffer(mesh->positions3D, file))
|
|
||||||
return false;
|
|
||||||
mesh->normals.reserve(header.nbPositions);
|
|
||||||
if(!readBuffer(mesh->normals, file))
|
|
||||||
return false;
|
|
||||||
if(header.flags & (1 << Mesh::MESH_TANGENT_SPACE))
|
|
||||||
{
|
|
||||||
mesh->tangents.reserve(header.nbPositions);
|
|
||||||
if(!readBuffer(mesh->tangents, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mesh->positions2D.reserve(header.nbPositions);
|
|
||||||
if(!readBuffer(mesh->positions2D, file))
|
|
||||||
return false;
|
|
||||||
mesh->setDepth(header.depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.nbInstances_offsets)
|
|
||||||
{
|
|
||||||
mesh->instances_offsets.reserve(header.nbInstances_offsets);
|
|
||||||
if(!readBuffer(mesh->instances_offsets, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.nbIndices)
|
|
||||||
{
|
|
||||||
mesh->indices.reserve(header.nbIndices);
|
|
||||||
if(!readBuffer(mesh->indices, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.flags & (1 << Mesh::MESH_TEXTURABLE))
|
|
||||||
{
|
|
||||||
mesh->texCoords.reserve(header.nbPositions);
|
|
||||||
if(!readBuffer(mesh->texCoords, file))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh->setIsBillboard(header.flags & (1 << Mesh::MESH_BILLBOARD));
|
|
||||||
mesh->setIsDoubleSided(header.flags & (1 << Mesh::MESH_DOUBLE_SIDED));
|
|
||||||
mesh->setIsShadowCaster(header.flags & (1 << Mesh::MESH_SHADOWED));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Material* deserializeMaterial(FILE *file)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Light* loadLight(const std::string &filename)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#ifndef SERIALIZERS_H
|
|
||||||
#define SERIALIZERS_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class Mesh;
|
|
||||||
class Light;
|
|
||||||
class Texture;
|
|
||||||
|
|
||||||
namespace Serializers
|
|
||||||
{
|
|
||||||
bool saveMesh(const std::string &filename, Mesh *mesh);
|
|
||||||
bool saveLight(const std::string &filename, Light *light);
|
|
||||||
|
|
||||||
Mesh* loadMesh(const std::string &filename);
|
|
||||||
Light* loadLight(const std::string &filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SERIALIZERS_H
|
|
Loading…
x
Reference in New Issue
Block a user