summaryrefslogblamecommitdiff
path: root/hw4/src/importOBJ.cpp
blob: ad1e4a83c1b6e08a0af5bfe6ebaf44632b695831 (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 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::binary | std::ifstream::in);
  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();

    // COMMENTS:
    if(key == '#' || key == ' ') 
    {
      std::string comment;
      ifs >> comment;  // comment: skip line
    }

    // VERTEX DATA:
    else 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; }
	}

	// store in polygon
        if(vt != -1) tidx.push_back(vt-1);
        if(vn != -1) nidx.push_back(vn-1);
        if(vi != -1) vidx.push_back(vi-1);

	// check if we did not eat the end-of-line chararters
	ifs.unget();
	c = ifs.get();
	if(c == '\r' || c == '\n') done = true;

	// eat remaining spaces
	c  = ifs.get();
	while(c == ' ')
	  c = ifs.get();

	// check again for end
	if(c == '\r' || c == '\n') done = true;
	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) );
        }
      }
    }
  }

  // Done.
}