Jump to content

  • Log In with Google      Sign In   
  • Create Account

#ActualMarkS

Posted 10 December 2012 - 05:20 PM

Or even better:

std::vector<float> vertexBuffer(fileSize);


I use vectors in my OBJ loader. I was going to mention it, but didn't want to complicate the issues. And I have a cold and am typing through a fog...

OBJ Loader.h

OBJ Loader.cpp

This will only load OBJ files with triangular faces. The interesting thing is that since I use vectors, I can load the OBJ file data in any order. Cut a vertex line and paste it between two face lines and the file will still load properly. I have a newer version that replaces the older c-style file handling functions (fread, fgetc, etc.) for the newer C++ versions, but I cannot find the code at the moment. Must be on another computer.

#2MarkS

Posted 10 December 2012 - 05:11 PM

Or even better:

std::vector<float> vertexBuffer(fileSize);


I use vectors in my OBJ loader. I was going to mention it, but didn't want to complicate the issues. And I have a cold and am typing through a fog...

OBJ Loader.h:
#ifndef __OBJ_LOADER__
#define __OBJ_LOADER__
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
class OBJ_vertex{
public:
OBJ_vertex(){}
~OBJ_vertex(){}
float GetX() const {return(x);}
void SetX(float _x) {x = _x;}
float GetY() const {return(y);}
void SetY(float _y) {y = _y;}
float GetZ() const {return(z);}
void SetZ(float _z) {z = _z;}
private:
float x;
float y;
float z;
};
class uv_coords{
public:
uv_coords(){}
~uv_coords(){}
float GetU() const {return(u);}
void SetU(float _u) {u = _u;}
float GetV() const {return(v);}
void SetV(float _v) {v = _v;}
private:
float u;
float v;
};
class face{
public:
face();
face(const face &right);
~face();
long GetNumVertices() const;
long GetNumNormals() const;
long GetNumUVs() const;
void AddVertex(long index);
long GetVertex(long index) const;
void AddNormal(long index);
long GetNormal(long index) const;
void AddUV(long index);
long GetUV(long index) const;
private:
vector<long>  *vertices;
vector<long>  *normals;
vector<long>  *uv;
};
class OBJ{
public:
OBJ();
~OBJ();
long GetNumVertices() const;
long GetNumNormals() const;
long GetNumUVs() const;
long GetNumFaces() const;
OBJ_vertex *GetVertex(long index) const;
OBJ_vertex *GetNormal(long index) const;
uv_coords *GetUV(long index) const;
face *GetFace(long index) const;
void LoadOBJ(string file_name);
void DumpOBJ(void);
private:
vector<OBJ_vertex> *vertices;
vector<OBJ_vertex> *normals;
vector<uv_coords> *uv;
vector<face>  *faces;
};
#endif

OBJ Loader.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "OBJ Loader.h"

face::face()
{
vertices = new vector<long>;
normals = new vector<long>;
uv = new vector<long>;
}
face::face(const face &right)
{
long i;
vertices = new vector<long>;
normals = new vector<long>;
uv = new vector<long>;
for(i = 0;i < right.vertices->size();i++)
  vertices->push_back(right.vertices->at(i));
for(i = 0;i < right.normals->size();i++)
  normals->push_back(right.normals->at(i));
for(i = 0;i < right.uv->size();i++)
  uv->push_back(right.uv->at(i));
}
face::~face()
{
delete vertices;
vertices = NULL;
delete normals;
normals = NULL;
delete uv;
uv = NULL;
}
long face::GetNumVertices() const
{
return(vertices->size());
}
long face::GetNumNormals() const
{
return(normals->size());
}
long face::GetNumUVs() const
{
return(uv->size());
}
void face::AddVertex(long index)
{
vertices->push_back(index);
}
long face::GetVertex(long index) const
{
if(index < 0 || index > vertices->size() - 1)
  return(NULL);
return(vertices->at(index));
}
void face::AddNormal(long index)
{
normals->push_back(index);
}
long face::GetNormal(long index) const
{
if(index < 0 || index > normals->size() - 1)
  return(NULL);
return(normals->at(index));
}
void face::AddUV(long index)
{
uv->push_back(index);
}
long face::GetUV(long index) const
{
if(index < 0 || index > uv->size() - 1)
  return(NULL);
return(uv->at(index));
}
OBJ::OBJ()
{
vertices = new vector<OBJ_vertex>;
normals = new vector<OBJ_vertex>;
uv = new vector<uv_coords>;
faces = new vector<face>;
}
OBJ::~OBJ()
{
delete vertices;
vertices = NULL;
delete normals;
normals = NULL;
delete uv;
uv = NULL;
delete faces;
faces = NULL;
}
long OBJ::GetNumVertices() const
{
return(vertices->size());
}
long OBJ::GetNumNormals() const
{
return(normals->size());
}
long OBJ::GetNumUVs() const
{
return(uv->size());
}
long OBJ::GetNumFaces() const
{
return(faces->size());
}
OBJ_vertex *OBJ::GetVertex(long index) const
{
if(index < 0 || index > vertices->size() - 1)
  return(NULL);
return(&vertices->at(index));
}
OBJ_vertex *OBJ::GetNormal(long index) const
{
if(index < 0 || index > normals->size() - 1)
  return(NULL);
return(&normals->at(index));
}
uv_coords *OBJ::GetUV(long index) const
{
if(index < 0 || index > uv->size() - 1)
  return(NULL);
return(&uv->at(index));
}
face *OBJ::GetFace(long index) const
{
if(index < 0 || index > faces->size() - 1)
  return(NULL);
return(&faces->at(index));
}
void OBJ::LoadOBJ(string file_name)
{
FILE  *fs;
char  c;
bool  done,has_normals,has_uvs;
OBJ_vertex vert;
uv_coords uvs;
face  *temp_face;
float  x,y,z;
float  u,v;
int   vert_ind,norm_ind,uv_ind;
int   read_count;
if(fopen_s(&fs,file_name.c_str(),"r") != 0)
  return;
done = false;
has_normals = false;
has_uvs = false;
while(!done)
{
  c = fgetc(fs);
  switch(c)
  {
   case '#': // Comment. Fall through
   case 'u': // Fall through
   case 's': // Fall through
   case 'g': // Group. Not supported. Fall through
	while(fgetc(fs) != '\n'); // Skip to the next line
   break;
   case EOF: // End of file reached. We be done.
	done = true;
   break;
   case 'v': // Loading vertices is easy. Faces, not so much...
	c = fgetc(fs); // The next character determines what type of vertex we are loading
	switch(c)
	{
	 case ' ': // Loading vertices
	  fscanf_s(fs,"%f %f %f\n",&x,&y,&z);
	  vert.SetX(x);
	  vert.SetY(y);
	  vert.SetZ(z);
	  vertices->push_back(vert);
	 break;
	 case 'n': // Loading normals
	  has_normals = true;
	  fscanf_s(fs,"%f %f %f\n",&x,&y,&z);
	  vert.SetX(x);
	  vert.SetY(y);
	  vert.SetZ(z);
	  normals->push_back(vert);
	 break;
	 case 't': // Loading UVs
	  has_uvs = true;
	  fscanf_s(fs,"%f %f\n",&u,&v);
	  uvs.SetU(u);
	  uvs.SetV(v);
	  uv->push_back(uvs);
	 break;
	 default: // Uh oh... What are we trying to read here? Someone screwed up their OBJ exporter...
	  cout << "Invalid vertex type: " << "v" << c << " Should be of type \"v \", \"vn\" or \"vt\"." << endl;
	  return;
	}
   break;
   case 'f':
	if(has_normals && has_uvs)
	{
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  norm_ind = 0;
	  uv_ind = 0;
	  read_count = fscanf_s(fs,"%d/%d/%d",&vert_ind,&uv_ind,&norm_ind);
	  if((read_count != 3) || (vert_ind == 0) || (uv_ind == 0) || (norm_ind == 0)) // Valid indices start at 1 in a .OBJ file. Don't know why... O.o
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1); // We want the indices to start at 0, so subtract 1.
	  temp_face->AddNormal(norm_ind - 1);
	  temp_face->AddUV(uv_ind - 1);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
	}else if(has_normals && !has_uvs){
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  norm_ind = 0;
	  read_count = fscanf_s(fs,"%d//%d",&vert_ind,&norm_ind);
	  if((read_count != 2) || (vert_ind == 0) || (norm_ind == 0))
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1);
	  temp_face->AddNormal(norm_ind - 1);
	  temp_face->AddUV(0);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
	}else if(!has_normals && has_uvs){
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  uv_ind = 0;
	  read_count = fscanf_s(fs,"%d/%d/",&vert_ind,&uv_ind);
	  if((read_count != 2) || (vert_ind == 0) || (uv_ind == 0))
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1);
	  temp_face->AddNormal(0);
	  temp_face->AddUV(uv_ind - 1);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
	}else if(!has_normals && !has_uvs){
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  read_count = fscanf_s(fs,"%d//",&vert_ind);
	  if((read_count != 1) || (vert_ind == 0))
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1);
	  temp_face->AddNormal(0);
	  temp_face->AddUV(0);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
	}
   break;
  }
}
fclose(fs);
}
void OBJ::DumpOBJ(void)
{
long i,j;
for(i = 0;i < GetNumVertices();i++)
  cout << GetVertex(i)->GetX() << " " << GetVertex(i)->GetY() << " " << GetVertex(i)->GetZ() << endl;
for(i = 0;i < GetNumNormals();i++)
  cout << GetNormal(i)->GetX() << " " << GetNormal(i)->GetY() << " " << GetNormal(i)->GetZ() << endl;
for(i = 0;i < GetNumUVs();i++)
  cout << GetUV(i)->GetU() << " " << GetUV(i)->GetV() << endl;
for(i = 0;i < GetNumFaces();i++)
{
  for(j = 0;j < GetFace(i)->GetNumVertices();j++)
   cout << GetFace(i)->GetVertex(j) << "/" << GetFace(i)->GetUV(j) << "/" << GetFace(i)->GetNormal(j) << " ";
  cout << endl;
}
}


The source tags screwed up the formatting. Huh. Anyway, this will only load OBJ files with triangular faces. The interesting thing is that since I use vectors, I can load the OBJ file data in any order. Cut a vertex line and paste it between two face lines and the file will still load properly. I have a newer version that replaces the older c-style file handling functions (fread, fgetc, etc.) for the newer C++ versions, but I cannot find the code at the moment. Must be on another computer.

#1MarkS

Posted 10 December 2012 - 05:00 PM

Or even better:

std::vector<float> vertexBuffer(fileSize);


I use vectors in my OBJ loader. I was going to mention it, but didn't want to complicate the issues. And I have a cold and am typing through a fog...

OBJ Loader.h:
#ifndef __OBJ_LOADER__
#define __OBJ_LOADER__
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
class OBJ_vertex{
public:
OBJ_vertex(){}
~OBJ_vertex(){}
float GetX() const {return(x);}
void SetX(float _x) {x = _x;}
float GetY() const {return(y);}
void SetY(float _y) {y = _y;}
float GetZ() const {return(z);}
void SetZ(float _z) {z = _z;}
private:
float x;
float y;
float z;
};
class uv_coords{
public:
uv_coords(){}
~uv_coords(){}
float GetU() const {return(u);}
void SetU(float _u) {u = _u;}
float GetV() const {return(v);}
void SetV(float _v) {v = _v;}
private:
float u;
float v;
};
class face{
public:
face();
face(const face &right);
~face();
long GetNumVertices() const;
long GetNumNormals() const;
long GetNumUVs() const;
void AddVertex(long index);
long GetVertex(long index) const;
void AddNormal(long index);
long GetNormal(long index) const;
void AddUV(long index);
long GetUV(long index) const;
private:
vector<long>  *vertices;
vector<long>  *normals;
vector<long>  *uv;
};
class OBJ{
public:
OBJ();
~OBJ();
long GetNumVertices() const;
long GetNumNormals() const;
long GetNumUVs() const;
long GetNumFaces() const;
OBJ_vertex *GetVertex(long index) const;
OBJ_vertex *GetNormal(long index) const;
uv_coords *GetUV(long index) const;
face *GetFace(long index) const;
void LoadOBJ(string file_name);
void DumpOBJ(void);
private:
vector<OBJ_vertex> *vertices;
vector<OBJ_vertex> *normals;
vector<uv_coords> *uv;
vector<face>  *faces;
};
#endif

OBJ Loader.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "OBJ Loader.h"
 
face::face()
{
vertices = new vector<long>;
normals = new vector<long>;
uv = new vector<long>;
}
face::face(const face &right)
{
long i;
vertices = new vector<long>;
normals = new vector<long>;
uv = new vector<long>;
for(i = 0;i < right.vertices->size();i++)
  vertices->push_back(right.vertices->at(i));
for(i = 0;i < right.normals->size();i++)
  normals->push_back(right.normals->at(i));
for(i = 0;i < right.uv->size();i++)
  uv->push_back(right.uv->at(i));
}
face::~face()
{
delete vertices;
vertices = NULL;
delete normals;
normals = NULL;
delete uv;
uv = NULL;
}
long face::GetNumVertices() const
{
return(vertices->size());
}
long face::GetNumNormals() const
{
return(normals->size());
}
long face::GetNumUVs() const
{
return(uv->size());
}
void face::AddVertex(long index)
{
vertices->push_back(index);
}
long face::GetVertex(long index) const
{
if(index < 0 || index > vertices->size() - 1)
  return(NULL);
return(vertices->at(index));
}
void face::AddNormal(long index)
{
normals->push_back(index);
}
long face::GetNormal(long index) const
{
if(index < 0 || index > normals->size() - 1)
  return(NULL);
return(normals->at(index));
}
void face::AddUV(long index)
{
uv->push_back(index);
}
long face::GetUV(long index) const
{
if(index < 0 || index > uv->size() - 1)
  return(NULL);
return(uv->at(index));
}
OBJ::OBJ()
{
vertices = new vector<OBJ_vertex>;
normals = new vector<OBJ_vertex>;
uv = new vector<uv_coords>;
faces = new vector<face>;
}
OBJ::~OBJ()
{
delete vertices;
vertices = NULL;
delete normals;
normals = NULL;
delete uv;
uv = NULL;
delete faces;
faces = NULL;
}
long OBJ::GetNumVertices() const
{
return(vertices->size());
}
long OBJ::GetNumNormals() const
{
return(normals->size());
}
long OBJ::GetNumUVs() const
{
return(uv->size());
}
long OBJ::GetNumFaces() const
{
return(faces->size());
}
OBJ_vertex *OBJ::GetVertex(long index) const
{
if(index < 0 || index > vertices->size() - 1)
  return(NULL);
return(&vertices->at(index));
}
OBJ_vertex *OBJ::GetNormal(long index) const
{
if(index < 0 || index > normals->size() - 1)
  return(NULL);
return(&normals->at(index));
}
uv_coords *OBJ::GetUV(long index) const
{
if(index < 0 || index > uv->size() - 1)
  return(NULL);
return(&uv->at(index));
}
face *OBJ::GetFace(long index) const
{
if(index < 0 || index > faces->size() - 1)
  return(NULL);
return(&faces->at(index));
}
void OBJ::LoadOBJ(string file_name)
{
FILE  *fs;
char  c;
bool  done,has_normals,has_uvs;
OBJ_vertex vert;
uv_coords uvs;
face  *temp_face;
float  x,y,z;
float  u,v;
int   vert_ind,norm_ind,uv_ind;
int   read_count;
if(fopen_s(&fs,file_name.c_str(),"r") != 0)
  return;
done = false;
has_normals = false;
has_uvs = false;
while(!done)
{
  c = fgetc(fs);
  switch(c)
  {
   case '#': // Comment. Fall through
   case 'u': // Fall through
   case 's': // Fall through
   case 'g': // Group. Not supported. Fall through
    while(fgetc(fs) != '\n'); // Skip to the next line
   break;
   case EOF: // End of file reached. We be done.
    done = true;
   break;
   case 'v': // Loading vertices is easy. Faces, not so much...
    c = fgetc(fs); // The next character determines what type of vertex we are loading
    switch(c)
    {
	 case ' ': // Loading vertices
	  fscanf_s(fs,"%f %f %f\n",&x,&y,&z);
	  vert.SetX(x);
	  vert.SetY(y);
	  vert.SetZ(z);
	  vertices->push_back(vert);
	 break;
	 case 'n': // Loading normals
	  has_normals = true;
	  fscanf_s(fs,"%f %f %f\n",&x,&y,&z);
	  vert.SetX(x);
	  vert.SetY(y);
	  vert.SetZ(z);
	  normals->push_back(vert);
	 break;
	 case 't': // Loading UVs
	  has_uvs = true;
	  fscanf_s(fs,"%f %f\n",&u,&v);
	  uvs.SetU(u);
	  uvs.SetV(v);
	  uv->push_back(uvs);
	 break;
	 default: // Uh oh... What are we trying to read here? Someone screwed up their OBJ exporter...
	  cout << "Invalid vertex type: " << "v" << c << " Should be of type \"v \", \"vn\" or \"vt\"." << endl;
	  return;
    }
   break;
   case 'f':
    if(has_normals && has_uvs)
    {
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  norm_ind = 0;
	  uv_ind = 0;
	  read_count = fscanf_s(fs,"%d/%d/%d",&vert_ind,&uv_ind,&norm_ind);
	  if((read_count != 3) || (vert_ind == 0) || (uv_ind == 0) || (norm_ind == 0)) // Valid indices start at 1 in a .OBJ file. Don't know why... O.o
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1); // We want the indices to start at 0, so subtract 1.
	  temp_face->AddNormal(norm_ind - 1);
	  temp_face->AddUV(uv_ind - 1);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
    }else if(has_normals && !has_uvs){
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  norm_ind = 0;
	  read_count = fscanf_s(fs,"%d//%d",&vert_ind,&norm_ind);
	  if((read_count != 2) || (vert_ind == 0) || (norm_ind == 0))
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1);
	  temp_face->AddNormal(norm_ind - 1);
	  temp_face->AddUV(0);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
    }else if(!has_normals && has_uvs){
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  uv_ind = 0;
	  read_count = fscanf_s(fs,"%d/%d/",&vert_ind,&uv_ind);
	  if((read_count != 2) || (vert_ind == 0) || (uv_ind == 0))
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1);
	  temp_face->AddNormal(0);
	  temp_face->AddUV(uv_ind - 1);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
    }else if(!has_normals && !has_uvs){
	 temp_face = new face;
	 while(fgetc(fs) != '\n')
	 {
	  vert_ind = 0;
	  read_count = fscanf_s(fs,"%d//",&vert_ind);
	  if((read_count != 1) || (vert_ind == 0))
	  {
	   delete temp_face;
	   temp_face = NULL;
	   cout << "Invalid vertex index." << endl;
	   return;
	  }
	  temp_face->AddVertex(vert_ind - 1);
	  temp_face->AddNormal(0);
	  temp_face->AddUV(0);
	 }
	 faces->push_back(*temp_face);
	 delete temp_face;
	 temp_face = NULL;
    }
   break;
  }
}
fclose(fs);
}
void OBJ::DumpOBJ(void)
{
long i,j;
for(i = 0;i < GetNumVertices();i++)
  cout << GetVertex(i)->GetX() << " " << GetVertex(i)->GetY() << " " << GetVertex(i)->GetZ() << endl;
for(i = 0;i < GetNumNormals();i++)
  cout << GetNormal(i)->GetX() << " " << GetNormal(i)->GetY() << " " << GetNormal(i)->GetZ() << endl;
for(i = 0;i < GetNumUVs();i++)
  cout << GetUV(i)->GetU() << " " << GetUV(i)->GetV() << endl;
for(i = 0;i < GetNumFaces();i++)
{
  for(j = 0;j < GetFace(i)->GetNumVertices();j++)
   cout << GetFace(i)->GetVertex(j) << "/" << GetFace(i)->GetUV(j) << "/" << GetFace(i)->GetNormal(j) << " ";
  cout << endl;
}
}

PARTNERS