libsegl/model/loadobj.cpp

241 lines
6.5 KiB
C++

#include "loadobj.h"
namespace segl {
LoadOBJ::LoadOBJ(std::string _filename) : Modelloader(_filename) {
}
bool LoadOBJ::load(Model *m) {
// Filestreams
std::ifstream file(filename.c_str());
std::ifstream matfile;
std::string inbuf; // TMP-Var
std::vector<std::string> v;
std::vector<std::string> v2;
int anz;
unsigned int vertanz=0, polyanz=0, matanz=0, texanz=0, normanz=0;
std::string materials;
// Punkt2D *texdata = 0;
// texdataanz = 0;
// Punkt3D *normdata = 0;
// normdata = 0;
Material *usemat;
if(!file)
return false;
// start counting items, read file
while(getline(file, inbuf)) {
anz = explode(inbuf, " ", &v);
if(!anz)
continue;
if(v[0]=="f")
polyanz++; // polygon
else if(v[0]=="v")
vertanz++; // vertex
else if(v[0]=="mtllib") {
if(anz>1)
materials = trim(v[1]);
// std::cout << "V1: " << v[1] << std::endl;
} else if(v[0]=="vt")
texanz++; // texcoord
else if(v[0]=="vn")
normanz++; // normal
}
if(materials!="") {
matfile.open((rbasename(filename)+materials).c_str());
if(matfile) {
while(getline(matfile, inbuf)) {
anz = explode(inbuf, " ", &v);
if(!anz)
continue;
if(v[0]=="newmtl")
matanz++;
}
}
}
// std::cout << "Vert: " << vertanz << " Poly: " << polyanz << " Mat: " << matanz << " (Matfile: " << materials << ") Norm: " << normanz << std::endl;
if(!vertanz || !polyanz)
return false;
if(m->isLoaded())
m->unload();
// Allocate memory for filecontent
m->meshdataanz = vertanz;
m->meshdata = new Punkt3D[vertanz];
m->polydataanz = polyanz;
m->polydata = new Meshpolygon[polyanz];
if(matanz) {
m->matdataanz = matanz;
m->matdata = new Material[matanz];
}
m->texdataanz = texanz;
m->texdata = new Punkt2D[matanz];
m->normdataanz = normanz;
m->normdata = new Punkt3D[normanz];
// Readout Material
matfile.clear();
matfile.seekg(0);
if(matanz&&matfile) { // Got milk.. eh.. material?
matanz = 0;
Material mat;
while(getline(matfile, inbuf)) {
anz = explode(inbuf, " ", &v);
if(!anz)
continue;
if(v[0]=="newmtl") {
if(matanz!=0)
m->matdata[matanz-1] = mat; // Push material
matanz++;
mat = Material();
mat.name = trim(v[1]);
} else if(v[0]=="Ka") {
if(anz<4)
continue;
mat.ambient.set(std::atof(v[1].c_str()), std::atof(v[2].c_str()), std::atof(v[3].c_str()));
} else if(v[0]=="Kd") {
if(anz<4)
continue;
mat.diffuse.set(std::atof(v[1].c_str()), std::atof(v[2].c_str()), std::atof(v[3].c_str()));
} else if(v[0]=="Ks") {
if(anz<4)
continue;
mat.specular.set(std::atof(v[1].c_str()), std::atof(v[2].c_str()), std::atof(v[3].c_str()));
}
}
// Last material wasnt pushed
if(matanz!=0)
m->matdata[matanz-1] = mat;
}
// Readout File
usemat = &(m->backupmat); // If material required but not avilable use backup
file.clear();
file.seekg(0);
polyanz = vertanz = normanz = texanz = 0; // Reset counters
while(getline(file, inbuf)) {
anz = explode(inbuf, " ", &v);
if(!anz)
continue;
if(v[0]=="v") {
if(anz<4)
continue;
m->meshdata[vertanz].set(std::atof(v[1].c_str()), std::atof(v[2].c_str()), std::atof(v[3].c_str()));
vertanz++;
} else if(v[0]=="vn") {
if(anz<4)
continue;
m->normdata[normanz].set(std::atof(v[1].c_str()), std::atof(v[2].c_str()), std::atof(v[3].c_str()));
normanz++;
} else if(v[0]=="vt") {
if(anz<3)
continue;
m->texdata[texanz].set(std::atof(v[1].c_str()), std::atof(v[2].c_str()));
texanz++;
} else if(v[0]=="f") {
if(anz<4)
continue;
unsigned int arr[3][3] = { {0,0,0}, {0,0,0}, {0,0,0} };
for(unsigned int i=0; i<3; i++) {
int zanz = explode(v[i+1], "/", &v2);
// std::cout << "explode " << v[i+1] << " anz " << zanz << std::endl;
if(zanz<3) {
if(zanz==1)
arr[i][0] = std::atoi(v2[0].c_str());
continue;
}
arr[i][0] = std::atoi(v2[0].c_str());
arr[i][1] = std::atoi(v2[1].c_str());
arr[i][2] = std::atoi(v2[2].c_str());
// std::cout << "Loaded: " << arr[i][0] << " " << arr[i][1] << " " << arr[i][2] << " " << std::endl;
// std::cout << "From: " << v2[0] << " " << v2[1] << " " << v2[2] << " " << std::endl;
}
if(arr[0][0])
m->polydata[polyanz].m1.point = &(m->meshdata[arr[0][0]-1]);
if(arr[0][1])
m->polydata[polyanz].m1.tex = &(m->texdata[arr[0][1]-1]);
if(arr[0][2])
m->polydata[polyanz].m1.normal = &(m->normdata[arr[0][2]-1]);
if(arr[1][0])
m->polydata[polyanz].m2.point = &(m->meshdata[arr[1][0]-1]);
if(arr[1][1])
m->polydata[polyanz].m2.tex = &(m->texdata[arr[1][1]-1]);
if(arr[1][2])
m->polydata[polyanz].m2.normal = &(m->normdata[arr[1][2]-1]);
if(arr[2][0])
m->polydata[polyanz].m3.point = &(m->meshdata[arr[2][0]-1]);
if(arr[2][1])
m->polydata[polyanz].m3.tex = &(m->texdata[arr[2][1]-1]);
if(arr[2][2])
m->polydata[polyanz].m3.normal = &(m->normdata[arr[2][2]-1]);
// std::cout << "POLY " << polyanz << std::endl;
polyanz++;
} else if(v[0]=="usemtl") {
if(anz<2)
continue;
std::string fterm = trim(v[1]);
for(unsigned int i=0; i < m->matdataanz; i++) {
if(m->matdata[i].name==fterm) {
usemat = &(m->matdata[i]);
break;
}
}
}
v.clear();
}
// Calculate bounding box and rad for sphere
float minx=m->meshdata[0].x, maxx=m->meshdata[0].x, miny=m->meshdata[0].y, maxy=m->meshdata[0].y, minz=m->meshdata[0].z, maxz=m->meshdata[0].z;
for(unsigned int i=0; i<m->meshdataanz; i++) {
m->boundingrad = std::max(m->boundingrad, abs(m->meshdata[i]));
minx = std::min(minx, m->meshdata[i].x);
maxx = std::max(maxx, m->meshdata[i].x);
miny = std::min(miny, m->meshdata[i].y);
maxy = std::max(maxy, m->meshdata[i].y);
minz = std::min(minz, m->meshdata[i].z);
maxz = std::max(maxz, m->meshdata[i].z);
}
// std::cout << "(" << minx << ", " << maxx << ") " << "(" << miny << ", " << maxy << ") " << "(" << minz << ", " << maxz << ") " << std::endl;
m->boundingbox.d.set(minx, miny, minz);
m->boundingbox.a.set(minx, miny, maxz);
m->boundingbox.b.set(maxx, miny, maxz);
m->boundingbox.c.set(maxx, miny, minz);
m->boundingbox.h.set(minx, maxy, minz);
m->boundingbox.e.set(minx, maxy, maxz);
m->boundingbox.f.set(maxx, maxy, maxz);
m->boundingbox.g.set(maxx, maxy, minz);
// m->boundingrad = std::max( std::abs(minx)+std::abs(maxx),
// std::max( std::abs(miny)+std::abs(maxy),
// std::abs(minz)+std::abs(maxz)));
m->loaded = true;
// std::cout << "Loaded!" << std::endl;
return true;
}
} // namespace segl