Skip to content

Instantly share code, notes, and snippets.

@tgfrerer
Created April 24, 2014 16:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tgfrerer/11260871 to your computer and use it in GitHub Desktop.
Save tgfrerer/11260871 to your computer and use it in GitHub Desktop.
ofMesh::load (modified to deal with more general .ply files)
//--------------------------------------------------------------
void ofMesh::load(string path){
ofFile is(path, ofFile::ReadOnly);
ofMesh& data = *this;
string line;
string error;
ofBuffer buffer(is);
ofMesh backup = data;
int orderVertices=-1;
int orderIndices=-1;
int vertexCoordsFound=0;
int colorCompsFound=0;
int texCoordsFound=0;
int normalsCoordsFound=0;
int currentVertex = 0;
int currentFace = 0;
bool floatColor = false;
enum State{
Header,
VertexDef,
FaceDef,
Vertices,
Normals,
Faces
};
data.clear();
State state = Header;
int lineNum = 0;
line = buffer.getFirstLine();
lineNum++;
if(line!="ply"){
error = "wrong format, expecting 'ply'";
goto clean;
}
line = buffer.getNextLine();
lineNum++;
if(line!="format ascii 1.0"){
error = "wrong format, expecting 'format ascii 1.0'";
goto clean;
}
while(!buffer.isLastLine()){
line = buffer.getNextLine();
lineNum++;
if(line.find("comment")==0){
continue;
}
if((state==Header || state==FaceDef) && line.find("element vertex")==0){
state = VertexDef;
orderVertices = MAX(orderIndices, 0)+1;
data.getVertices().resize(ofToInt(line.substr(15)));
continue;
}
if((state==Header || state==VertexDef) && line.find("element face")==0){
state = FaceDef;
orderIndices = MAX(orderVertices, 0)+1;
data.getIndices().resize(ofToInt(line.substr(13))*3);
continue;
}
if(state==VertexDef && Poco::RegularExpression("^property float [xyzw]$").match(line)){
vertexCoordsFound++;
continue;
}
if(state==VertexDef && Poco::RegularExpression("^property float [rgba]$").match(line)){
colorCompsFound++;
data.getColors().resize(data.getVertices().size());
floatColor = true;
continue;
}
if(state==VertexDef && Poco::RegularExpression("^property uchar (red)|(green)|(blue)$").match(line)){
colorCompsFound++;
data.getColors().resize(data.getVertices().size());
floatColor = false;
continue;
}
if(state==VertexDef && Poco::RegularExpression("^property float [uv]$").match(line)){
texCoordsFound++;
data.getTexCoords().resize(data.getVertices().size());
continue;
}
if(state==VertexDef && Poco::RegularExpression("^property float n[xyzw]$").match(line)){
normalsCoordsFound++;
if (normalsCoordsFound==3) data.getNormals().resize(data.getVertices().size());
continue;
}
if(state==FaceDef && line.find("property list")!=0 && line!="end_header"){
error = "wrong face definition";
goto clean;
}
if(line=="end_header"){
if(data.hasColors() && colorCompsFound!=3 && colorCompsFound!=4){
error = "data has color coordiantes but not correct number of components. Found " + ofToString(colorCompsFound) + " expecting 3 or 4";
goto clean;
}
if(data.hasNormals() && normalsCoordsFound!=3){
error = "data has normal coordiantes but not correct number of components. Found " + ofToString(normalsCoordsFound) + " expecting 3";
goto clean;
}
if(!data.hasVertices()){
ofLogWarning("ofMesh") << "load(): mesh loaded from \"" << path << "\" has no vertices";
}
if(orderVertices==-1) orderVertices=9999;
if(orderIndices==-1) orderIndices=9999;
if(orderVertices < orderIndices){
state = Vertices;
}else {
state = Faces;
}
continue;
}
if(state==Vertices){
stringstream sline;
sline.str(line);
ofVec4f v;
sline >> v.x;
sline >> v.y;
if(vertexCoordsFound>2) sline >> v.z;
if(vertexCoordsFound==4) sline >> v.w;
data.getVertices()[currentVertex] = ofVec3f(v);
if(colorCompsFound>0){
if (floatColor){
ofFloatColor c;
sline >> c.r;
sline >> c.g;
sline >> c.b;
if(colorCompsFound>3) sline >> c.a;
data.getColors()[currentVertex] = c;
}else{
int r, g, b, a = 255;
sline >> r;
sline >> g;
sline >> b;
if(colorCompsFound>3) sline >> a;
data.getColors()[currentVertex] = ofColor(r, g, b, a);
}
}
if(texCoordsFound>0){
ofVec2f uv;
sline >> uv.x;
sline >> uv.y;
float dummy;
if (texCoordsFound > 2) sline >> dummy;
if (texCoordsFound > 3) sline >> dummy;
data.getTexCoords()[currentVertex] = uv;
}
if (normalsCoordsFound>0){
ofVec3f n;
sline >> n.x;
sline >> n.y;
sline >> n.z;
float dummy;
if (normalsCoordsFound>3) sline >> dummy;
data.getNormals()[currentVertex] = n;
}
currentVertex++;
if(currentVertex==data.getNumVertices()){
if(orderVertices<orderIndices){
state = Faces;
}else{
state = Vertices;
}
}
continue;
}
if(state==Faces){
stringstream sline;
sline.str(line);
int numV;
sline >> numV;
if(numV!=3){
error = "face not a triangle";
goto clean;
}
int i;
sline >> i;
data.getIndices()[currentFace*3] = i;
sline >> i;
data.getIndices()[currentFace*3+1] = i;
sline >> i;
data.getIndices()[currentFace*3+2] = i;
currentFace++;
if(currentFace==data.getNumIndices()/3){
if(orderVertices<orderIndices){
state = Vertices;
}else{
state = Faces;
}
}
continue;
}
}
return;
clean:
ofLogError("ofMesh") << "load(): " << lineNum << ":" << error;
ofLogError("ofMesh") << "load(): \"" << line << "\"";
data = backup;
}
void ofMesh::save(string path, bool useBinary) const{
ofFile os(path, ofFile::WriteOnly);
const ofMesh& data = *this;
os << "ply" << endl;
if(useBinary) {
os << "format binary_little_endian 1.0" << endl;
} else {
os << "format ascii 1.0" << endl;
}
if(data.getNumVertices()){
os << "element vertex " << data.getNumVertices() << endl;
os << "property float x" << endl;
os << "property float y" << endl;
os << "property float z" << endl;
if(data.getNumColors()){
os << "property uchar red" << endl;
os << "property uchar green" << endl;
os << "property uchar blue" << endl;
os << "property uchar alpha" << endl;
}
if(data.getNumTexCoords()){
os << "property float u" << endl;
os << "property float v" << endl;
}
if(data.getNumNormals()){
os << "property float nx" << endl;
os << "property float ny" << endl;
os << "property float nz" << endl;
}
}
unsigned char faceSize = 3;
if(data.getNumIndices()){
os << "element face " << data.getNumIndices() / faceSize << endl;
os << "property list uchar int vertex_indices" << endl;
} else if(data.getMode() == OF_PRIMITIVE_TRIANGLES) {
os << "element face " << data.getNumVertices() / faceSize << endl;
os << "property list uchar int vertex_indices" << endl;
}
os << "end_header" << endl;
for(int i = 0; i < data.getNumVertices(); i++){
if(useBinary) {
os.write((char*) &data.getVertices()[i], sizeof(ofVec3f));
} else {
os << data.getVertex(i).x << " " << data.getVertex(i).y << " " << data.getVertex(i).z;
}
if(data.getNumColors()){
// VCG lib / MeshLab don't support float colors, so we have to cast
ofColor cur = data.getColors()[i];
if(useBinary) {
os.write((char*) &cur, sizeof(ofColor));
} else {
os << " " << (int) cur.r << " " << (int) cur.g << " " << (int) cur.b << " " << (int) cur.a;
}
}
if(data.getNumTexCoords()){
if(useBinary) {
os.write((char*) &data.getTexCoords()[i], sizeof(ofVec2f));
} else {
os << " " << data.getTexCoord(i).x << " " << data.getTexCoord(i).y;
}
}
if(data.getNumNormals()){
if(useBinary) {
os.write((char*) &data.getNormals()[i], sizeof(ofVec3f));
} else {
os << " " << data.getNormal(i).x << " " << data.getNormal(i).y << " " << data.getNormal(i).z;
}
}
if(!useBinary) {
os << endl;
}
}
if(data.getNumIndices()) {
for(int i = 0; i < data.getNumIndices(); i += faceSize) {
if(useBinary) {
os.write((char*) &faceSize, sizeof(unsigned char));
for(int j = 0; j < faceSize; j++) {
int curIndex = data.getIndex(i + j);
os.write((char*) &curIndex, sizeof(int));
}
} else {
os << (int) faceSize << " " << data.getIndex(i) << " " << data.getIndex(i+1) << " " << data.getIndex(i+2) << endl;
}
}
} else if(data.getMode() == OF_PRIMITIVE_TRIANGLES) {
for(int i = 0; i < data.getNumVertices(); i += faceSize) {
int indices[] = {i, i + 1, i + 2};
if(useBinary) {
os.write((char*) &faceSize, sizeof(unsigned char));
for(int j = 0; j < faceSize; j++) {
os.write((char*) &indices[j], sizeof(int));
}
} else {
os << (int) faceSize << " " << indices[0] << " " << indices[1] << " " << indices[2] << endl;
}
}
}
//TODO: add index generation for other OF_PRIMITIVE cases
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment