/******************************************************************/
/* This file is part of the homework assignments for CSCI-427/527 */
/* at The College of William & Mary and authored by Pieter Peers. */
/* No part of this file, whether altered or in original form, can */
/* be distributed or used outside the context of CSCI-427/527 */
/* without consent of either the College of William & Mary or */
/* Pieter Peers. */
/******************************************************************/
#include <memory>
#include <string>
#include <cassert>
#include <fstream>
#include "vec3d.h"
#include "vec2d.h"
#include "importOBJ.h"
#include "errorMessage.h"
void skipLine(std::ifstream& ifs)
{
unsigned char c = ifs.get();
while(ifs.good() && c != '\r' && c != '\n') c = ifs.get();
while(ifs.good() && (c == '\r' || c == '\n')) c = ifs.get();
ifs.unget();
}
void importOBJ(const std::string filename, std::vector<triangle>& triangle_list)
{
// define buffers
auto vertex_list = std::make_shared<std::vector<vec3d>>();
auto normal_list = std::make_shared<std::vector<vec3d>>();
auto textureCoord_list = std::make_shared<std::vector<vec2d>>();
// open obj file
std::ifstream ifs(filename, std::ifstream::in | std::ifstream::binary);
if(!ifs.is_open())
errorMessage("Unable to import OBJ (%s).", filename.c_str());
// read line by line
unsigned char key;
while(ifs.good())
{
// get key
key = ifs.get();
// VERTEX DATA:
if(key == 'v')
{
// get vertex data
key = ifs.get();
// Vertex Coordinate
if(key == ' ')
{
vec3d v;
ifs >> v.x >> v.y >> v.z;
vertex_list->push_back(v);
}
// Texture Coordinate
else if(key == 't')
{
vec2d t;
ifs >> t.u >> t.v;
textureCoord_list->push_back(t);
}
// Normal
else if(key == 'n')
{
vec3d n;
ifs >> n.x >> n.y >> n.z;
normal_list->push_back(n);
}
// Unknown => ERROR
else errorMessage("Unknown OBJ vertex-key: v%c.", key);
}
// POLYGON:
else if(key == 'f')
{
// temp data structures
std::vector<unsigned int> vidx;
std::vector<unsigned int> nidx;
std::vector<unsigned int> tidx;
// get polygon data
// can be either:
// 1) v0 v1 .. vn
// 2) v0//n0 v1//n1 .. vn//nn
// 3) v0/t0 v1/t1 ... vn/tn
// 4) v0/t0/n0 ... vn/tn/nn
bool done=false;
while(!done)
{
// read entry
signed int vi, vt=-1, vn=-1;
ifs >> vi;
unsigned char c = ifs.get();
if(c == '/')
{
c = ifs.get();
if(c != '/') { ifs.unget(); ifs >> vt; c = ifs.get(); }
if(c == '/') { ifs >> vn; c = ifs.get(); }
}
// sanity check
assert(vt != 0 && vn != 0 && vi != 0);
// store in polygon
if(vt != -1) { assert(vt-1 < textureCoord_list->size()); tidx.push_back(vt-1); }
if(vn != -1) { assert(vn-1 < normal_list->size()); nidx.push_back(vn-1); }
if(vi != -1) { assert(vi-1 < vertex_list->size()); vidx.push_back(vi-1); }
// eat spaces and end-of-lines
ifs.unget();
c = ifs.get();
while(ifs.good() && (c == ' ' ||c == '\r' || c == '\n'))
{
if(c == '\r' || c == '\n') done = true;
c = ifs.get();
}
ifs.unget();
// sanity check
assert(tidx.empty() || tidx.size() == vidx.size());
assert(nidx.empty() || nidx.size() == vidx.size());
// store triangle
if(vidx.size() >= 3)
{
size_t m=vidx.size() - 2;
size_t l=vidx.size() - 1;
if(tidx.empty() && nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list) );
if(tidx.empty() && !nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list,
nidx[0], nidx[m], nidx[l], normal_list) );
if(!tidx.empty() && nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list,
tidx[0], tidx[m], tidx[l], textureCoord_list) );
if(!tidx.empty() && !nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list,
nidx[0], nidx[m], nidx[l], normal_list,
tidx[0], tidx[m], tidx[l], textureCoord_list) );
}
}
}
else { ifs.unget(); skipLine(ifs); }
}
// Done.
}