335 lines
12 KiB
C++
335 lines
12 KiB
C++
#include <fstream>
|
|
#include "../inc/assimp/Importer.hpp"
|
|
#include "../inc/assimp/scene.h"
|
|
#include "../inc/assimp/postprocess.h"
|
|
#include "../Renderer.h"
|
|
#include "ObjLoader.h"
|
|
|
|
ObjLoader* ObjLoader::mInstance = NULL;
|
|
|
|
|
|
void ObjLoader::Create() {
|
|
if (mInstance == NULL)
|
|
mInstance = new ObjLoader();
|
|
}
|
|
|
|
void ObjLoader::Destroy() {
|
|
if (mInstance != NULL)
|
|
delete mInstance;
|
|
mInstance = NULL;
|
|
}
|
|
|
|
ObjLoader* ObjLoader::Instance() {
|
|
return mInstance;
|
|
}
|
|
|
|
|
|
//************************************
|
|
// Load OBJ file with ASSIMP library
|
|
// Parse to scene, using binary file if possible
|
|
//************************************
|
|
bool ObjLoader::Load(const char* fileName, Scene &scene) {
|
|
|
|
mVertexOffset = 0;
|
|
mIndexOffset = 0;
|
|
mTextureOffset = 0;
|
|
mBinaryFileName = "";
|
|
|
|
// Try to load binary scene, otherwise parse ASSIMP scene
|
|
if (!Read(fileName, scene)) {
|
|
// Load OBJ with ASSIMP
|
|
Assimp::Importer importer;
|
|
const aiScene* loadedScene = importer.ReadFile(fileName, aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_FlipUVs | aiProcess_GenSmoothNormals);
|
|
if (!loadedScene) {
|
|
// If bad allocation, try loading without joining identical vertices
|
|
const char* t = importer.GetErrorString();
|
|
if (strcmp(t, "bad allocation") == 0)
|
|
loadedScene = importer.ReadFile(fileName, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals);
|
|
if (!loadedScene)
|
|
return false;
|
|
}
|
|
|
|
// Load textures, only uses diffuse texture
|
|
auto s1 = std::string(fileName);
|
|
auto path = s1.substr(0, s1.find_last_of("\\/")).append("/");
|
|
std::vector<std::string> textures;
|
|
std::vector<float> reflectivenesses(loadedScene->mNumMaterials);
|
|
textures.resize(loadedScene->mNumMaterials, std::string());
|
|
for (unsigned m = 0; m < loadedScene->mNumMaterials; ++m) {
|
|
const aiMaterial* currentMat = loadedScene->mMaterials[m];
|
|
aiString dummy;
|
|
aiString* textureFile = &dummy;
|
|
aiGetMaterialTexture(currentMat, aiTextureType::aiTextureType_DIFFUSE, 0, textureFile);
|
|
if (textureFile->data[0] != '\0') {
|
|
textures[m] = std::string(path).append(textureFile->C_Str());
|
|
//aiGetMaterialInteger(currentMat, aiMaterialProperty::)
|
|
/*textures[m] = Renderer::Load2DTexture();
|
|
if (mTextureOffset < 0) mTextureOffset = textures[m];*/
|
|
}
|
|
float reflectivity = 1.f;
|
|
aiGetMaterialFloat(currentMat, AI_MATKEY_OPACITY, &reflectivity);
|
|
reflectivity = 1.f - reflectivity;
|
|
reflectivenesses[m] = reflectivity;
|
|
//printf("%f\n", reflectivity);
|
|
}
|
|
|
|
for (unsigned m = 0; m < loadedScene->mNumMeshes; ++m) {
|
|
const aiMesh* currentMesh = loadedScene->mMeshes[m];
|
|
size_t currentVertex = scene.vertices.size();
|
|
size_t currentIndex = scene.indices.size();
|
|
|
|
// Fill vertex positions
|
|
for (unsigned i = 0; i < currentMesh->mNumVertices; i++) {
|
|
aiVector3D pos = currentMesh->mVertices[i];
|
|
scene.vertices.push_back(glm::vec3(pos.x, pos.y, pos.z));
|
|
}
|
|
|
|
// Fill vertices texture coordinates
|
|
// Assume 1 set of UV coordinates, AssImp supports 8 sets
|
|
if (currentMesh->HasTextureCoords(0)) {
|
|
// If this mesh has uv coordinates, then the whole scene should have them.
|
|
scene.uvs.resize(scene.vertices.size() - currentMesh->mNumVertices);
|
|
|
|
// Read the uvs
|
|
for (unsigned i = 0; i < currentMesh->mNumVertices; i++) {
|
|
aiVector3D UVW = currentMesh->mTextureCoords[0][i];
|
|
scene.uvs.push_back(glm::vec2(UVW.x, UVW.y));
|
|
}
|
|
}
|
|
// Fill empty spots
|
|
if (scene.uvs.size() != 0)
|
|
scene.uvs.resize(scene.vertices.size(), glm::vec2(0));
|
|
|
|
// Fill vertices normals
|
|
if (currentMesh->HasNormals()) {
|
|
for (unsigned i = 0; i < currentMesh->mNumVertices; i++) {
|
|
aiVector3D n = currentMesh->mNormals[i];
|
|
scene.normals.push_back(glm::vec3(n.x, n.y, n.z));
|
|
}
|
|
}
|
|
// Fill empty spots
|
|
scene.normals.resize(scene.vertices.size(), glm::vec3(0));
|
|
|
|
// Fill vertex colors (if they are set)
|
|
if (currentMesh->HasVertexColors(0))
|
|
{
|
|
// If this mesh has colored vertices, then the whole scene should have them.
|
|
scene.colors.resize(scene.vertices.size() - currentMesh->mNumVertices);
|
|
|
|
// Read the vertex coordinates
|
|
for (unsigned i = 0; i < currentMesh->mNumVertices; i++) {
|
|
aiColor4D col = currentMesh->mColors[0][i];
|
|
scene.colors.push_back(glm::vec3(col.r, col.g, col.b));
|
|
}
|
|
}
|
|
// If the scene has colors, fill them with the color white for the whole scene
|
|
if (scene.colors.size() != 0)
|
|
scene.colors.resize(scene.vertices.size(), glm::vec3(1));
|
|
|
|
// Fill triangle indices
|
|
for (unsigned i = 0; i < currentMesh->mNumFaces; i++) {
|
|
scene.indices.push_back((unsigned)(currentVertex + currentMesh->mFaces[i].mIndices[0]));
|
|
scene.indices.push_back((unsigned)(currentVertex + currentMesh->mFaces[i].mIndices[1]));
|
|
scene.indices.push_back((unsigned)(currentVertex + currentMesh->mFaces[i].mIndices[2]));
|
|
}
|
|
|
|
// Save mesh
|
|
Mesh mesh;
|
|
mesh.offset = (unsigned)currentIndex;
|
|
mesh.size = (unsigned)(scene.indices.size() - currentIndex);
|
|
mesh.texture = textures[currentMesh->mMaterialIndex];
|
|
mesh.hasUVs = currentMesh->HasTextureCoords(0);
|
|
mesh.hasVertexColors = currentMesh->HasVertexColors(0);
|
|
mesh.reflectivity = reflectivenesses[currentMesh->mMaterialIndex];
|
|
scene.meshes.push_back(mesh);
|
|
|
|
if (mVertexOffset <= 0) mVertexOffset = currentVertex;
|
|
if (mIndexOffset <= 0) mIndexOffset = currentIndex;
|
|
}
|
|
if (!Write(fileName, scene))
|
|
return false;
|
|
textures.clear();
|
|
}
|
|
// The scene pointer is deleted automatically by importer
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
ObjLoader::ObjLoader() {
|
|
mVertexOffset = 0;
|
|
mIndexOffset = 0;
|
|
mTextureOffset = 0;
|
|
mBinaryFileName = "";
|
|
}
|
|
|
|
|
|
ObjLoader::~ObjLoader() {
|
|
}
|
|
|
|
//************************************
|
|
// Get binary file name
|
|
//************************************
|
|
void ObjLoader::GetBinaryFileName(const char* fileName) {
|
|
if (mBinaryFileName.empty()) {
|
|
mBinaryFileName = fileName;
|
|
mBinaryFileName.append(".bin");
|
|
}
|
|
}
|
|
|
|
bool ReadFile(std::ifstream& sceneInFile, Scene &scene)
|
|
{
|
|
try
|
|
{
|
|
int readVertexOffset, readIndexOffset, readTextureOffset;
|
|
sceneInFile.read((char*)&readVertexOffset, sizeof(int));
|
|
sceneInFile.read((char*)&readIndexOffset, sizeof(int));
|
|
sceneInFile.read((char*)&readTextureOffset, sizeof(int));
|
|
|
|
unsigned verticesSize, uvsSize, normalsSize, colorsSize, indicesSize, meshesSize;
|
|
|
|
sceneInFile.read((char*)&verticesSize, sizeof(unsigned));
|
|
sceneInFile.read((char*)&uvsSize, sizeof(unsigned));
|
|
sceneInFile.read((char*)&normalsSize, sizeof(unsigned));
|
|
sceneInFile.read((char*)&colorsSize, sizeof(unsigned));
|
|
sceneInFile.read((char*)&indicesSize, sizeof(unsigned));
|
|
sceneInFile.read((char*)&meshesSize, sizeof(unsigned));
|
|
|
|
// Check if the sizes are valid. If they are not, we're probably dealing with an old file
|
|
if (meshesSize > verticesSize || (colorsSize != 0 && colorsSize != verticesSize) || normalsSize != verticesSize || (uvsSize != 0 && uvsSize != verticesSize))
|
|
return false;
|
|
|
|
if (!scene.uvs.empty() || uvsSize != 0)
|
|
scene.uvs.resize(scene.vertices.size() + verticesSize, glm::vec2(0));
|
|
scene.normals.resize(scene.normals.size() + normalsSize);
|
|
if (!scene.colors.empty() || colorsSize != 0)
|
|
scene.colors.resize(scene.vertices.size() + verticesSize, glm::vec3(1));
|
|
scene.indices.resize(scene.indices.size() + indicesSize);
|
|
scene.meshes.resize(scene.meshes.size() + meshesSize);
|
|
scene.vertices.resize(scene.vertices.size() + verticesSize);
|
|
|
|
if (verticesSize != 0) sceneInFile.read((char*)&scene.vertices[scene.vertices.size() - verticesSize], sizeof(glm::vec3) * verticesSize);
|
|
if (sceneInFile.eof()) return false;
|
|
if (uvsSize != 0) sceneInFile.read((char*)&scene.uvs[scene.uvs.size() - uvsSize], sizeof(glm::vec2) * uvsSize);
|
|
if (sceneInFile.eof()) return false;
|
|
if (normalsSize != 0) sceneInFile.read((char*)&scene.normals[scene.normals.size() - normalsSize], sizeof(glm::vec3) * normalsSize);
|
|
if (sceneInFile.eof()) return false;
|
|
if (colorsSize != 0) sceneInFile.read((char*)&scene.colors[scene.colors.size() - colorsSize], sizeof(glm::vec3) * colorsSize);
|
|
if (sceneInFile.eof()) return false;
|
|
if (indicesSize != 0) sceneInFile.read((char*)&scene.indices[scene.indices.size() - indicesSize], sizeof(unsigned) * indicesSize);
|
|
if (sceneInFile.eof()) return false;
|
|
|
|
for (unsigned i = 0; i < meshesSize; i++) {
|
|
if (sceneInFile.eof()) return false;
|
|
Mesh mesh;
|
|
sceneInFile.read((char*)&mesh.offset, sizeof(unsigned));
|
|
sceneInFile.read((char*)&mesh.size, sizeof(unsigned));
|
|
unsigned int textureSize;
|
|
sceneInFile.read((char*)&textureSize, sizeof(unsigned int));
|
|
char* texture = new char[textureSize + 1];
|
|
sceneInFile.read((char*)&texture[0], textureSize);
|
|
texture[textureSize] = '\0';
|
|
mesh.texture = std::string(texture);
|
|
if (sceneInFile.eof()) return false;
|
|
sceneInFile.read((char*)&mesh.hasUVs, sizeof(bool));
|
|
if (sceneInFile.eof()) return false;
|
|
sceneInFile.read((char*)&mesh.hasVertexColors, sizeof(bool));
|
|
sceneInFile.read((char*)&mesh.reflectivity, sizeof(float));
|
|
delete[] texture;
|
|
scene.meshes[i] = mesh;
|
|
}
|
|
return true;
|
|
}
|
|
catch (std::exception& ex)
|
|
{
|
|
printf("An exception occured while reading the mesh cache file: %s", ex.what());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//************************************
|
|
// Read scene from binary file
|
|
//************************************
|
|
bool ObjLoader::Read(const char* fileName, Scene &scene) {
|
|
|
|
GetBinaryFileName(fileName);
|
|
std::ifstream sceneInFile(mBinaryFileName, std::ios::binary);
|
|
|
|
if (sceneInFile.good()) {
|
|
mVertexOffset = (unsigned)scene.vertices.size();
|
|
mIndexOffset = (unsigned)scene.indices.size();
|
|
|
|
unsigned verticesSize = (unsigned)scene.vertices.size();
|
|
unsigned uvsSize = (unsigned)scene.uvs.size();
|
|
unsigned normalsSize = (unsigned)scene.normals.size();
|
|
unsigned colorsSize = (unsigned)scene.colors.size();
|
|
unsigned indicesSize = (unsigned)scene.indices.size();
|
|
unsigned meshesSize = (unsigned)scene.meshes.size();
|
|
|
|
bool readSucces = ReadFile(sceneInFile, scene);
|
|
if (!readSucces)
|
|
{
|
|
// Revert the scene if reading failed
|
|
scene.vertices.resize(verticesSize); scene.vertices.shrink_to_fit();
|
|
scene.uvs.resize(uvsSize); scene.uvs.shrink_to_fit();
|
|
scene.normals.resize(normalsSize); scene.normals.shrink_to_fit();
|
|
scene.colors.resize(colorsSize); scene.colors.shrink_to_fit();
|
|
scene.indices.resize(indicesSize); scene.indices.shrink_to_fit();
|
|
scene.meshes.resize(meshesSize); scene.meshes.shrink_to_fit();
|
|
|
|
}
|
|
sceneInFile.close();
|
|
|
|
return readSucces;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//************************************
|
|
// Write scene to binary file
|
|
//************************************
|
|
bool ObjLoader::Write(const char* fileName, Scene &scene) {
|
|
|
|
GetBinaryFileName(fileName);
|
|
std::ofstream sceneOutFile(mBinaryFileName, std::ios::binary);
|
|
|
|
unsigned verticesSize = (unsigned)scene.vertices.size();
|
|
unsigned uvsSize = (unsigned)scene.uvs.size();
|
|
unsigned normalsSize = (unsigned)scene.normals.size();
|
|
unsigned colorsSize = (unsigned)scene.colors.size();
|
|
unsigned indicesSize = (unsigned)scene.indices.size();
|
|
unsigned meshesSize = (unsigned)scene.meshes.size();
|
|
|
|
sceneOutFile.write((char*)&mVertexOffset, sizeof(int));
|
|
sceneOutFile.write((char*)&mIndexOffset, sizeof(int));
|
|
sceneOutFile.write((char*)&mTextureOffset, sizeof(int));
|
|
|
|
sceneOutFile.write((char*)&verticesSize, sizeof(unsigned));
|
|
sceneOutFile.write((char*)&uvsSize, sizeof(unsigned));
|
|
sceneOutFile.write((char*)&normalsSize, sizeof(unsigned));
|
|
sceneOutFile.write((char*)&colorsSize, sizeof(unsigned));
|
|
sceneOutFile.write((char*)&indicesSize, sizeof(unsigned));
|
|
sceneOutFile.write((char*)&meshesSize, sizeof(unsigned));
|
|
|
|
if (verticesSize > 0) sceneOutFile.write((char*)&scene.vertices[0], sizeof(glm::vec3) * verticesSize);
|
|
if (uvsSize > 0) sceneOutFile.write((char*)&scene.uvs[0], sizeof(glm::vec2) * uvsSize);
|
|
if (normalsSize > 0) sceneOutFile.write((char*)&scene.normals[0], sizeof(glm::vec3) * normalsSize);
|
|
if (colorsSize > 0) sceneOutFile.write((char*)&scene.colors[0], sizeof(glm::vec3) * colorsSize);
|
|
if (indicesSize > 0) sceneOutFile.write((char*)&scene.indices[0], sizeof(unsigned) * indicesSize);
|
|
|
|
unsigned int textureSize;
|
|
for (Mesh mesh : scene.meshes) {
|
|
sceneOutFile.write((char*)&mesh.offset, sizeof(unsigned));
|
|
sceneOutFile.write((char*)&mesh.size, sizeof(unsigned));
|
|
textureSize = (unsigned)mesh.texture.size();
|
|
sceneOutFile.write((char*)&textureSize, sizeof(unsigned int));
|
|
sceneOutFile.write(mesh.texture.c_str(), textureSize);
|
|
sceneOutFile.write((char*)&mesh.hasUVs, sizeof(bool));
|
|
sceneOutFile.write((char*)&mesh.hasVertexColors, sizeof(bool));
|
|
sceneOutFile.write((char*)&mesh.reflectivity, sizeof(float));
|
|
}
|
|
sceneOutFile.close();
|
|
|
|
return true;
|
|
} |