summaryrefslogblamecommitdiff
path: root/hw6/src/importOBJ.cpp
blob: 53354be959fad2bc2ef45fd488d93166d660d0a3 (plain) (tree)























































































































































                                                                                                                               
/******************************************************************/
/* 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.
}