Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
421 lines (330 sloc) 9.06 KB
/*
* ofxOBJModel.cpp
*
*/
#include "ofxOBJModel.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#pragma mark string utils
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
return split(s, delim, elems);
}
#pragma mark ofxOBJModel
bool ofxOBJModel::load(string path) {
filePath = path;
path = ofToDataPath(path, true);
string line;
for(int i = 0; i < meshes.size(); i++) {
delete meshes[i];
}
meshes.clear();
ObjMesh *currMesh = NULL;
// this is a list of all points
// that we can drop after parsing
vector<ofPoint> points;
// obj file format vertexes are 1-indexed
points.push_back(ofPoint());
ifstream myfile (path.c_str());
if (myfile.is_open()) {
while (! myfile.eof()) {
getline (myfile,line);
// parse the obj format here.
//
// the only things we're interested in is
// lines beginning with 'g' - this says start of new object
// lines beginning with 'v ' - coordinate of a vertex
// lines beginning with 'f ' - specifies a face of a shape
// we take each number before the slash as the index
// of the vertex to join up to create a face.
if(line.find("g ")==0) { // new object definition
currMesh = new ObjMesh(line.substr(2));
meshes.push_back(currMesh);
} else if(line.find("v ")==0) { // new vertex
points.push_back(parseVertex(line));
} else if(line.find("f ")==0) { // face definition
if(currMesh!=NULL) {
line = line.substr(2); // lop off "f "
vector<string> indices = split(line, ' ');
// remove any texcoords (/xxx's)
for(int i = 0; i < indices.size(); i++) {
int slashPos = indices[i].find("/");
if(slashPos!=-1) {
indices[i] = indices[i].substr(0, slashPos);
}
}
ObjFace *face = new ObjFace();
for(int i = 0; i < indices.size(); i++) {
face->points.push_back(points[atoi(indices[i].c_str())]);
}
currMesh->addFace(face);
}
}
}
myfile.close();
printf("Successfully loaded %s\n-----\nVertices: %d\nMeshes: %d\n", path.c_str(), points.size(), meshes.size());
return true;
} else {
printf("Couldn't find the OBJ file %s\n", path.c_str());
return false;
}
}
bool ofxOBJModel::save(string file) {
if(file=="") {
file = filePath;
if(filePath=="") {
filePath = "untitled.obj";
}
}
file = ofToDataPath(file, true);
string contents = "";
int vertexIndex = 1;
string faceStrings = "";
for(int i = 0; i < meshes.size(); i++) {
contents += "g " + meshes[i]->name + "\n";
for(int j = 0; j < meshes[i]->faces.size(); j++) {
string faceString = "f";
for(int k = 0; k < meshes[i]->faces[j]->points.size(); k++) {
ofPoint p = meshes[i]->faces[j]->points[k];
contents += "v " + ofToString(p.x) + " " + ofToString(p.y) + " " + ofToString(p.z) + "\n";
faceString += " " + ofToString(vertexIndex);
vertexIndex++;
}
faceStrings += faceString + "\n";
}
contents += "\n" + faceStrings + "\n";
faceStrings = "";
}
ofstream myfile (file.c_str());
if (myfile.is_open()) {
myfile << contents;
myfile.close();
return true;
} else {
printf("Could not write to file\n");
return false;
}
}
/**
* Takes a line from the obj file beginning with a "v " and
* turns it into an ofPoint.
*/
ofPoint ofxOBJModel::parseVertex(string line) {
ofPoint p;
if(line.find("v ")!=0) {
printf("Warning, line does not have vertex info in it: \"%s\"\n", line.c_str());
return p;
}
line = line.substr(2);
vector<string> elements = split(line, ' ');
if(elements.size()!=3) {
printf("Error line does not have 3 coordinates: \"%s\"\n", line.c_str());
return p;
}
p.x = atof(elements[0].c_str());
p.y = atof(elements[1].c_str());
p.z = atof(elements[2].c_str());
return p;
}
void ofxOBJModel::draw() {
for(int i = 0; i < meshes.size(); i++) {
meshes[i]->draw();
}
}
vector<string> ofxOBJModel::getMeshNames() {
vector<string> meshNames;
for(int i = 0; i < meshes.size(); i++) {
meshNames.push_back(meshes[i]->name);
}
return meshNames;
}
void ofxOBJModel::getBounds(ofPoint *minPoint, ofPoint *maxPoint) {
minPoint->x = minPoint->y = minPoint->z = 100000;
maxPoint->x = maxPoint->y = maxPoint->z = -100000;
for(int i = 0; i < meshes.size(); i++) {
ofPoint min, max;
meshes[i]->getBounds(&min, &max);
if(max.x>maxPoint->x) maxPoint->x = max.x;
if(max.y>maxPoint->y) maxPoint->y = max.y;
if(max.z>maxPoint->z) maxPoint->z = max.z;
if(min.x<minPoint->x) minPoint->x = min.x;
if(min.y<minPoint->y) minPoint->y = min.y;
if(min.z<minPoint->z) minPoint->z = min.z;
}
}
ObjMesh *ofxOBJModel::getMesh(string name) {
for(int i = 0; i < meshes.size(); i++) {
if(meshes[i]->name==name) {
return meshes[i];
}
}
return NULL;
}
#pragma mark ObjMesh
ObjMesh::ObjMesh(string _name) {
name = _name;
}
ObjMesh::~ObjMesh() {
for(int i = 0; i < faces.size(); i++) {
delete faces[i];
}
faces.clear();
}
void ObjMesh::addFace(ObjFace* face) {
faces.push_back(face);
}
void ObjMesh::draw() {
for(int i = 0; i < faces.size(); i++) {
faces[i]->draw();
}
}
void ObjMesh::getBounds(ofPoint *minPoint, ofPoint *maxPoint) {
minPoint->x = minPoint->y = minPoint->z = 100000;
maxPoint->x = maxPoint->y = maxPoint->z = -100000;
for(int i = 0; i < faces.size(); i++) {
for(int j = 0; j < faces[i]->points.size(); j++) {
ofPoint p = faces[i]->points[j];
if(p.x>maxPoint->x) maxPoint->x = p.x;
if(p.y>maxPoint->y) maxPoint->y = p.y;
if(p.z>maxPoint->z) maxPoint->z = p.z;
if(p.x<minPoint->x) minPoint->x = p.x;
if(p.y<minPoint->y) minPoint->y = p.y;
if(p.z<minPoint->z) minPoint->z = p.z;
}
}
}
// this moves the whole mesh by the specified amount
void ObjMesh::translate(float dx, float dy, float dz) {
ofPoint delta = ofPoint(dx, dy, dz);
for(int i = 0; i < faces.size(); i++) {
for(int j = 0; j < faces[i]->points.size(); j++) {
faces[i]->points[j] += delta;
}
}
}
// makes the code look nicer.
#define FOR_EACH_POINT_IN_MESH for(int i = 0; i < faces.size(); i++) for(int j = 0; j < faces[i]->points.size(); j++)
// these functions move the extremity of the mesh.
// eg moveTop() will move the top vertex/vertices by
// the specified amount.
void ObjMesh::moveTop (float delta) {
float extrema = 100000;
// find the extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].y<extrema) {
extrema = faces[i]->points[j].y;
}
}
// alter all the values that have the same extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].y==extrema) {
faces[i]->points[j].y += delta;
}
}
}
void ObjMesh::moveBottom (float delta) {
float extrema = -100000;
// find the extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].y>extrema) {
extrema = faces[i]->points[j].y;
}
}
// alter all the values that have the same extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].y==extrema) {
faces[i]->points[j].y += delta;
}
}
}
void ObjMesh::moveLeft (float delta) {
float extrema = 100000;
// find the extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].x<extrema) {
extrema = faces[i]->points[j].x;
}
}
// alter all the values that have the same extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].x==extrema) {
faces[i]->points[j].x += delta;
}
}
}
void ObjMesh::moveRight (float delta) {
float extrema = -100000;
// find the extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].x>extrema) {
extrema = faces[i]->points[j].x;
}
}
// alter all the values that have the same extreme
FOR_EACH_POINT_IN_MESH {
if(faces[i]->points[j].x==extrema) {
faces[i]->points[j].x += delta;
}
}
}
/**
* Changes the direction of all the vertices.
* i.e. clockwise to anti-clockwise
*/
void ObjMesh::flipDirection() {
for(int i = 0; i < faces.size(); i++) {
faces[i]->flipDirection();
}
}
/**
* Shifts the points along one
*/
void ObjMesh::shiftPointsLeft() {
for(int i = 0; i < faces.size(); i++) {
faces[i]->shiftPointsLeft();
}
}
void ObjMesh::shiftPointsRight() {
for(int i = 0; i < faces.size(); i++) {
faces[i]->shiftPointsRight();
}
}
#pragma mark ObjFace
#include "ofxVec3f.h"
void ObjFace::draw() {
ofxVec3f right = points[1] - points[0];
ofxVec3f down = points[2] - points[0];
normal = right.cross(down);
glNormal3f(normal.x, normal.y, normal.z);
glBegin(GL_POLYGON);
for(int i = 0; i < points.size(); i++) {
glVertex3f(points[i].x, points[i].y, points[i].z);
}
glEnd();
}
/**
* Changes the direction of all the vertices.
* i.e. clockwise to anti-clockwise
*/
void ObjFace::flipDirection() {
std::reverse(points.begin(), points.end());
}
/**
* Shifts the points along one
*/
void ObjFace::shiftPointsLeft() {
std::rotate(points.begin(), points.begin()+points.size()-1, points.end());
}
void ObjFace::shiftPointsRight() {
std::rotate(points.begin(), points.begin()+1, points.end());
}
Jump to Line
Something went wrong with that request. Please try again.