SparrowEngine/src/tools/loader.cpp
2016-03-16 17:33:18 +01:00

336 lines
10 KiB
C++

#include "loader.h"
#include <fstream>
#include <streambuf>
#include <cstring>
#include <image.h>
#include "../resourcemanager.h"
#include <SFML/Graphics/Image.hpp>
#include <meshbuilder.h>
#include <phongmaterial.h>
#include "../sparrowrenderer/src/texture.h"
#include <iostream>
std::string Loader::obj_directory = "";
std::string Loader::mtl_directory = "";
std::string Loader::tex_directory = "";
std::string* Loader::loadTextFile(const std::string &filename)
{
std::ifstream t(filename);
std::string *str = new std::string();
t.seekg(0, std::ios::end);
str->reserve(t.tellg());
t.seekg(0, std::ios::beg);
str->assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
return str;
}
Image* Loader::loadImage(const std::string &filename, bool hasAlpha)
{
sf::Image sfImg;
sfImg.loadFromFile(tex_directory+filename);
Image* img = new Image();
img->depth = hasAlpha ? 32 : 24;
img->width = sfImg.getSize().x;
img->height = sfImg.getSize().y;
int size = img->width*img->height*(img->depth/8);
img->allocate(size);
const sf::Uint8 *pixels = sfImg.getPixelsPtr();
if(hasAlpha)
memcpy(img->pixels, pixels, size);
else
{
sf::Uint8 *ptr = (sf::Uint8*)img->pixels;
for(int i=0; i<img->width*img->height; ++i)
memcpy(ptr + i*3, pixels + i*4, 3);
}
return img;
}
std::vector<Mesh*> Loader::loadMesh(const std::string &filename){
std::vector<Mesh*> meshes;
std::vector<glm::vec3> pos;
std::vector<glm::vec3> norm;
std::vector<glm::vec2> tex;
std::string line;
Material* defaultMat = RESOURCE_GET(Material, "default");
if(defaultMat == NULL)
{
defaultMat = new PhongMaterial();
RESOURCE_ADD(defaultMat,Material,"default");
}
Material* currentMat = defaultMat;
std::ifstream file(obj_directory + filename);
if(!file.is_open())
{
fprintf(stderr, "can't load %s.\n", filename.c_str());
return meshes;
}
MeshBuilder* currentMesh = new MeshBuilder();
meshes.push_back(currentMesh);
currentMesh->setMaterial(currentMat);
std::getline(file, line);
while(!file.eof())
{
if(line.length() == 0) // line vide
{
std::getline(file, line);
continue;
}
switch(line[0])
{
case 'v':
//vertex attribute
switch(line[1])
{
case ' ': // vertex position
{
glm::vec3 p;
std::sscanf(line.c_str(),"v %f %f %f",&(p.x),&(p.y),&(p.z));
pos.push_back(p);
break;
}
case 't': // texCoord
{
glm::vec2 t;
std::sscanf(line.c_str(),"vt %f %f",&(t.x),&(t.y));
tex.push_back(t);
break;
}
case 'n': // normal
{
glm::vec3 n;
std::sscanf(line.c_str(),"vn %f %f %f",&(n.x),&(n.y),&(n.z));
norm.push_back(n);
break;
}
}
break;
case 'f': // face
{
int tab[9];
std::sscanf(line.c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d",tab,tab+1,tab+2,tab+3,tab+4,tab+5,tab+6,tab+7,tab+8);
//TODO: check sscanf success
int nb_vertices = currentMesh->positions.size();
currentMesh->addTriangle(nb_vertices, nb_vertices+1, nb_vertices+2);
for(int i=0; i<3; ++i)
{
if(norm.size() == 0)
{
if(tex.size() == 0)
currentMesh->addPosition(pos[tab[i]-1]);
else
currentMesh->addVertex(pos[tab[i]-1], tex[tab[i+1]-1]);
}
else
{
if(tex.size() == 0)
currentMesh->addVertex(pos[tab[i]-1], norm[tab[i+2]-1]);
else
currentMesh->addVertex(pos[tab[i]-1], norm[tab[i+2]-1], tex[tab[i+1]-1]);
}
}
}
break;
case 'g':
currentMesh = new MeshBuilder();
meshes.push_back(currentMesh);
currentMesh->setMaterial(currentMat);
break;
case 'm': // mtllib
{
char mat_filename[256];
std::sscanf(line.c_str(),"mtllib %s",mat_filename);
loadMTL(std::string(mat_filename));
break;
}
case 'u':
{
// usemtl
char mat_name[256];
std::sscanf(line.c_str(),"usemtl %s",mat_name);
std::string material_name(mat_name);
currentMat = RESOURCE_GET(Material, material_name);
if(currentMat == NULL)
{
fprintf(stderr, "cannot find any material named : %s.\n", material_name.c_str());
currentMat = new PhongMaterial();
RESOURCE_ADD(currentMat,Material,material_name);
}
currentMesh->setMaterial(currentMat);
}
break;
default:
case '#':
// comment
break;
}
std::getline(file,line);
}
for(std::size_t i=0; i<meshes.size(); ++i)
{
if(meshes[i]->indices.size() == 0)
{
meshes[i] = meshes.back();
meshes.pop_back();
--i;
}
}
return meshes;
}
//move this to an utils file ?
std::vector<std::string> split(const std::string &line, char sep){
std::vector<std::string> tokens;
std::size_t start=0, end=0;
while((end = line.find(sep,start)) != std::string::npos){
tokens.push_back(line.substr(start,end-start));
start=end+1;
}
tokens.push_back(line.substr(start));
return tokens;
}
//load MTL
bool Loader::loadMTL(const std::string &filename)
{
std::string line;
std::ifstream file(mtl_directory + filename);
if(!file.is_open())
{
fprintf(stderr, "can't load %s.\n", filename.c_str());
return false;
}
PhongMaterial* mat = NULL;
bool hasNormalMap = false;
std::getline(file,line);
while(!file.eof())
{
if(line.length() == 0)
{
std::getline(file,line);
continue;
}
//QStringList tokens = line.split(' ');
std::vector<std::string> tokens = split(line,' ');
if(tokens[0].substr(0,1) == "#")
{
// this is a comment
}
else if((tokens[0] == "newmtl") && tokens.size() == 2)
{
mat = new PhongMaterial();
RESOURCE_ADD(mat,Material,tokens[1]);
}
else if((tokens[0].compare("Ka") == 0) && tokens.size() == 4)
{
mat->ambient.r = std::stof(tokens[1]);
mat->ambient.g = std::stof(tokens[2]);
mat->ambient.b = std::stof(tokens[3]);
}
else if(tokens[0].compare("Kd") == 0 && tokens.size() == 4)
{
mat->diffuse.r = std::stof(tokens[1]);
mat->diffuse.g = std::stof(tokens[2]);
mat->diffuse.b = std::stof(tokens[3]);
}
else if(tokens[0].compare("Ks") == 0 && tokens.size() == 4)
{
mat->specular.r = std::stof(tokens[1]);
mat->specular.g = std::stof(tokens[2]);
mat->specular.b = std::stof(tokens[3]);
}
else if(tokens[0].compare("Ns") == 0 && tokens.size() == 2)
{
mat->shininess = std::stof(tokens[1]);
}
else if((tokens[0].substr(0,4) == "map_") && tokens.size() == 2)
{
if(tokens[0].compare("map_Ka") == 0){
mat->ambient_texture = RESOURCE_GET(Texture,tokens[1]);
if (mat->ambient_texture == NULL){
mat->ambient_texture = new Texture(loadImage(tokens[1]));
RESOURCE_ADD(mat->ambient_texture,Texture,tokens[1]);
}
} else if(tokens[0].compare("map_Kd") == 0) {
mat->diffuse_texture = RESOURCE_GET(Texture,tokens[1]);
if (mat->diffuse_texture == NULL){
mat->diffuse_texture = new Texture(loadImage(tokens[1]));
RESOURCE_ADD(mat->diffuse_texture,Texture,tokens[1]);
}
} else if(tokens[0].compare("map_Ks") == 0) {
mat->specular_texture = RESOURCE_GET(Texture,tokens[1]);
if (mat->specular_texture == NULL){
mat->specular_texture = new Texture(loadImage(tokens[1]));
RESOURCE_ADD(mat->specular_texture,Texture,tokens[1]);
}
} else if(tokens[0].compare("map_Normal") == 0) {
mat->normal_map = RESOURCE_GET(Texture,tokens[1]);
if (mat->normal_map == NULL){
mat->normal_map = new Texture(loadImage(tokens[1]));
RESOURCE_ADD(mat->normal_map,Texture,tokens[1]);
}
hasNormalMap = true;
} else if(tokens[0].compare("map_d") == 0) {
mat->alpha_mask = RESOURCE_GET(Texture,tokens[1]);
if (mat->alpha_mask == NULL){
mat->alpha_mask = new Texture(loadImage(tokens[1]));
RESOURCE_ADD(mat->alpha_mask,Texture,tokens[1]);
}
} else
fprintf(stderr, "unsupported material property : \"%s\"\n", tokens[0].c_str());
}
else
fprintf(stderr, "unsupported material property : \"%s\"\n", tokens[0].c_str());
std::getline(file,line);
}
return hasNormalMap;
}
void Loader::setObjDirectory(std::string dir_){
obj_directory = dir_;
}
void Loader::setMtlDirectory(std::string dir_){
mtl_directory = dir_;
}
void Loader::setTexDirectory(std::string dir_){
tex_directory = dir_;
}
/*
//glfinish
void temp_glfinish(){
for(std::size_t i=0; i<images.size(); ++i)
{
if(images[i]){
images[i]->initGL();
todos[i].target = images[i]->texture;
delete images[i];
}
}
}
*/