//-------------------------------------------------------------- bool load(const string& path, ofMesh& mesh) { ofFile file(path, ofFile::ReadOnly, true); if (!file.exists()) { ofLogError("ofxBinaryMesh::load") << "Cannot open file at " << path; return false; } mesh.clear(); int numVerts = 0; file.read((char *)(&numVerts), sizeof(int)); if (numVerts > 0) { mesh.getVertices().resize(numVerts); file.read((char *)(&(mesh.getVertices())[0]), sizeof(ofPoint) * numVerts); } int numNormals = 0; file.read((char *)(&numNormals), sizeof(int)); if (numNormals > 0) { mesh.getNormals().resize(numNormals); file.read((char *)(&(mesh.getNormals())[0]), sizeof(ofPoint) * numNormals); } int numTexCoords = 0; file.read((char *)(&numTexCoords), sizeof(int)); if (numTexCoords > 0) { mesh.getTexCoords().resize(numTexCoords); file.read((char *)(&(mesh.getTexCoords())[0]), sizeof(ofVec2f) * numTexCoords); } int numColors = 0; file.read((char *)(&numColors), sizeof(int)); if (numColors > 0) { mesh.getColors().resize(numColors); file.read((char *)(&(mesh.getColors())[0]), sizeof(ofFloatColor) * numColors); } int numIndices = 0; file.read((char *)(&numIndices), sizeof(int)); if (numIndices > 0) { mesh.getIndices().resize(numIndices); file.read((char *)(&(mesh.getIndices())[0]), sizeof(ofIndexType) * numIndices); } file.close(); return true; }
ofMesh & ofBitmapStringGetMesh(const string & text, int x, int y){ int len = (int)text.length(); //float yOffset = 0; float fontSize = 8.0f; bool bOrigin = false; float sx = x; float sy = y-fontSize; ofDrawBitmapCharacterStart(text.size()); for(int c = 0; c < len; c++){ if(text[c] == '\n'){ sy += bOrigin ? -1 : 1 * (fontSize*1.7); sx = x; //glRasterPos2f(x,y + (int)yOffset); } else if (text[c] >= 32){ // < 32 = control characters - don't draw // solves a bug with control characters // getting drawn when they ought to not be ofDrawBitmapCharacter(text[c], (int)sx, (int)sy); sx += fontSize; } } //We do this because its way faster charMesh.getVertices().resize(vC); charMesh.getTexCoords().resize(vC); return charMesh; }
//--------------------------------------------------------------------- void ofDrawBitmapCharacterEnd(){ if( vC > 0 ){ charMesh.getVertices().resize(vC); charMesh.getTexCoords().resize(vC); bitmappedFontTexture.bind(); ofPtr<ofGLProgrammableRenderer> programmableRenderer = ofGetGLProgrammableRenderer(); if (!programmableRenderer){ #ifndef TARGET_OPENGLES // this temporarily enables alpha testing, // which discards pixels unless their alpha is 1.0f glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0); #endif }else{ // glPush/PopAttrib is deprecated + we are doing the alpha test through a shader programmableRenderer->setAlphaBitmapText(true); } charMesh.draw(); if (!programmableRenderer){ #ifndef TARGET_OPENGLES glPopAttrib(); #endif }else{ programmableRenderer->setAlphaBitmapText(false); } bitmappedFontTexture.unbind(); } }
//--------------------------------------------------------------------- void ofDrawBitmapCharacter(int character, int x , int y){ if(!bBitmapTexturePrepared){ prepareBitmapTexture(); } if (character < 128) { float posTexW = (float)(character % 16)/16.0f; float posTexH = ((int)(character / 16.0f))/16.0f; float texY1 = posTexH; float texY2 = posTexH+heightTex; //TODO: look into a better fix. //old ofDrawBitmapString was 3 pixels higher, so this version renders text in a different position. //3 pixel adjustment corrects that when y is flpped 5 when it's not. int yOffset = 14; if(!ofIsVFlipped()){ y += 5; y += yOffset; yOffset *= -1; }else{ y -= 3; } charMesh.getTexCoords()[vC].set(posTexW,texY1); charMesh.getTexCoords()[vC+1].set(posTexW + widthTex,texY1); charMesh.getTexCoords()[vC+2].set(posTexW+widthTex,texY2); charMesh.getTexCoords()[vC+3].set(posTexW + widthTex,texY2); charMesh.getTexCoords()[vC+4].set(posTexW,texY2); charMesh.getTexCoords()[vC+5].set(posTexW,texY1); charMesh.getVertices()[vC].set(x,y); charMesh.getVertices()[vC+1].set(x+8,y); charMesh.getVertices()[vC+2].set(x+8,y+yOffset); charMesh.getVertices()[vC+3].set(x+8,y+yOffset); charMesh.getVertices()[vC+4].set(x,y+yOffset); charMesh.getVertices()[vC+5].set(x,y); vC += 6; } }
void ofxObjLoader::save(string path, ofMesh& mesh){ path = ofToDataPath(path); GLuint writeMode = GLM_NONE; GLMmodel* m = new GLMmodel(); if(mesh.getNumVertices() > 0){ m->numvertices = mesh.getNumVertices(); m->vertices = new GLfloat[m->numvertices*3+1]; memcpy(&m->vertices[3], &mesh.getVertices()[0].x, sizeof(ofVec3f) * mesh.getNumVertices()); } else { ofLogError("ofxObjLoader::save -- No vertices to save!"); return; } if(mesh.getNumNormals() > 0){ m->numnormals = mesh.getNumNormals(); m->normals = new GLfloat[m->numnormals*3+1]; memcpy(&m->normals[3], &mesh.getNormals()[0].x, sizeof(ofVec3f)*mesh.getNumNormals()); writeMode |= GLM_SMOOTH; } if(mesh.getNumTexCoords() > 0){ m->numtexcoords = mesh.getNumTexCoords(); m->texcoords = new GLfloat[m->numtexcoords*2+1]; memcpy(&m->texcoords[2], &mesh.getTexCoords()[0].x, sizeof(ofVec2f)*mesh.getNumTexCoords()); writeMode |= GLM_TEXTURE; } if(mesh.getNumIndices() > 0){ //create triangles m->numtriangles = mesh.getNumIndices()/3; m->triangles = new GLMtriangle[m->numtriangles]; //add them all to one group m->groups = new GLMgroup(); m->groups->next = NULL; m->groups->material = NULL; string name = "ofMesh"; m->groups->name = (char*)malloc(sizeof(char) * name.length()+1); strcpy(m->groups->name, name.c_str()); m->groups->numtriangles = mesh.getNumIndices()/3; m->groups->triangles = new GLuint[m->groups->numtriangles]; m->numgroups = 1; for(int i = 0; i < mesh.getNumIndices()/3; i++){ memcpy(m->triangles[i].vindices, &mesh.getIndices()[i*3], sizeof(GLuint)*3); memcpy(m->triangles[i].nindices, &mesh.getIndices()[i*3], sizeof(GLuint)*3); memcpy(m->triangles[i].tindices, &mesh.getIndices()[i*3], sizeof(GLuint)*3); m->groups->triangles[i] = i; } } glmWriteOBJ(m, (char*)path.c_str(), writeMode); glmDelete(m); }
//--------------------------------------------------------------------- void ofDrawBitmapCharacterStart(int stringLength){ charMesh.getVertices().resize(6 * stringLength); charMesh.getTexCoords().resize(6 * stringLength); if(!bBitmapTexturePrepared){ prepareBitmapTexture(); } vC = 0; }
//--------------------------------------------------------------------- static void addBitmapCharacter(ofMesh & charMesh, int & vertexCount, int character, int x , int y, bool vFlipped){ if (character < 128) { float posTexW = (float)(character % 16)/16.0f; float posTexH = ((int)(character / 16.0f))/16.0f; float texY1 = posTexH; float texY2 = posTexH+heightTex; //TODO: look into a better fix. //old ofDrawBitmapString was 3 pixels higher, so this version renders text in a different position. //3 pixel adjustment corrects that when y is flpped 5 when it's not. int yOffset = 14; if(!vFlipped){ y += 5; y += yOffset; yOffset *= -1; }else{ y -= 3; } size_t vC = vertexCount; charMesh.getTexCoords()[vC] = {posTexW,texY1}; charMesh.getTexCoords()[vC+1] = {posTexW + widthTex,texY1}; charMesh.getTexCoords()[vC+2] = {posTexW+widthTex,texY2}; charMesh.getTexCoords()[vC+3] = {posTexW + widthTex,texY2}; charMesh.getTexCoords()[vC+4] = {posTexW,texY2}; charMesh.getTexCoords()[vC+5] = {posTexW,texY1}; charMesh.getVertices()[vC] = glm::vec3(x,y,0.f); charMesh.getVertices()[vC+1] = glm::vec3(x+8,y,0.f); charMesh.getVertices()[vC+2] = glm::vec3(x+8,y+yOffset,0.f); charMesh.getVertices()[vC+3] = glm::vec3(x+8,y+yOffset,0.f); charMesh.getVertices()[vC+4] = glm::vec3(x,y+yOffset,0.f); charMesh.getVertices()[vC+5] = glm::vec3(x,y,0.f); vertexCount += 6; } }
void addForheadToFaceMesh(ofMesh & input){ if (input.getVertices().size() != 66) return; static int forehead[10] = {0,17,18,19,20,/*21,22,*/23,24,25,26,16}; // skipping 21 and 22 because there is a triangle that overlaps somehow ofPoint extras[10]; ofVec2f texture[10]; for (int i = 0; i < 10; i++){ extras[i] = input.getVertices()[forehead[i]] + (input.getVertices()[27] - input.getVertices()[33]); texture[i] = input.getTexCoords()[forehead[i]] + (input.getTexCoords()[27] - input.getTexCoords()[33]); input.addVertex(extras[i]); input.addTexCoord(texture[i]); } for (int i = 0; i < (10-1); i++){ // a b c // b c d; int a = forehead[i]; int b = 66 + i; int c = forehead[i+1]; input.addIndex(a); input.addIndex(b); input.addIndex(c); int d = 66 + i + 1; input.addIndex(b); input.addIndex(c); input.addIndex(d); } }
void ofxMesh::fromMesh(const ofMesh & mesh){ if (mesh.hasVertices()) { getVertices()=mesh.getVertices(); } if (mesh.hasColors()) { getColors()=mesh.getColors(); } if (mesh.hasNormals()) { getNormals()=mesh.getNormals(); } if (mesh.hasTexCoords()) { getTexCoords()=mesh.getTexCoords(); } if (mesh.hasIndices()) { getIndices()=mesh.getIndices(); } }
void ofxMesh::toMesh(ofMesh & mesh){ mesh.clear(); if (hasVertices()) { mesh.getVertices()=getVertices(); } if (hasColors()) { mesh.getColors()=getColors(); } if (hasNormals()) { mesh.getNormals()=getNormals(); } if (hasTexCoords()) { mesh.getTexCoords()=getTexCoords(); } if (hasIndices()) { mesh.getIndices()=getIndices(); } }
glmMesh toGlm(const ofMesh &_mesh){ glmMesh mesh; for (auto &it : _mesh.getColors()) { mesh.addColor(toGlm(it)); } for (auto &it : _mesh.getVertices()) { mesh.addVertex(toGlm(it)); } for (auto &it : _mesh.getNormals()) { mesh.addNormal(toGlm(it)); } for (auto &it : _mesh.getTexCoords()) { mesh.addTexCoord(toGlm(it)); } for (auto &it : _mesh.getIndices()) { mesh.addIndex(toGlm(it)); } GLenum drawMode = ofGetGLPrimitiveMode(_mesh.getMode()); if (drawMode == GL_POINTS) { mesh.setDrawMode(POINTS); } else if (drawMode == GL_LINES){ mesh.setDrawMode(LINES); } else if (drawMode == GL_LINE_STRIP){ mesh.setDrawMode(LINE_STRIP); } else if (drawMode == GL_TRIANGLES){ mesh.setDrawMode(TRIANGLES); } else if (drawMode == GL_TRIANGLE_STRIP){ mesh.setDrawMode(TRIANGLE_STRIP); } return mesh; }
void CloudsVisualSystem3DModelLoader::facetMesh( ofMesh& smoothedMesh, ofMesh& targetMesh ) { //get our vertex, uv and face info vector<ofVec3f>& v = smoothedMesh.getVertices(); vector<ofVec2f>& uv = smoothedMesh.getTexCoords(); vector<ofIndexType>& indices = smoothedMesh.getIndices(); bool hasTC = smoothedMesh.getNumTexCoords(); //use these to store our new mesh info vector<ofVec3f> facetedVertices( indices.size() ); vector<ofVec3f> facetedNormals( indices.size() ); vector<ofVec2f> facetedTexCoords; if(hasTC){ facetedTexCoords.resize( indices.size() ); } vector<ofIndexType> facetedIndices( indices.size() ); //store vertex and uv data for (int i=0; i < indices.size(); i++) { facetedIndices[i] = i; facetedVertices[i] = v[indices[i]]; if(hasTC) facetedTexCoords[i] = uv[indices[i]]; } //calculate our face normals ofVec3f n; for (int i=0; i < facetedIndices.size(); i+=3) { n = normalFrom3Points( facetedVertices[i], facetedVertices[i+1], facetedVertices[i+2]); facetedNormals[i] = n; facetedNormals[i+1] = n; facetedNormals[i+2] = n; } //setup our faceted mesh. this should still work if our targetMesh is our smoothMesh targetMesh.clear(); targetMesh.addVertices( facetedVertices ); targetMesh.addNormals( facetedNormals ); if(hasTC) targetMesh.addTexCoords( facetedTexCoords ); targetMesh.addIndices( facetedIndices ); }
//-------------------------------------------------------------- void save(const string& path, const ofMesh& mesh) { ofFile file(path, ofFile::WriteOnly, true); int numVerts = mesh.getNumVertices(); file.write((char *)(&numVerts), sizeof(int)); if (numVerts > 0) { file.write((char *)(&(mesh.getVertices())[0]), sizeof(ofPoint) * numVerts); } int numNormals = mesh.getNumNormals(); file.write((char *)(&numNormals), sizeof(int)); if (numNormals > 0) { file.write((char *)(&(mesh.getNormals())[0]), sizeof(ofPoint) * numNormals); } int numTexCoords = mesh.getNumTexCoords(); file.write((char *)(&numTexCoords), sizeof(int)); if (numTexCoords > 0) { file.write((char *)(&(mesh.getTexCoords())[0]), sizeof(ofVec2f) * numTexCoords); } int numColors = mesh.getNumColors(); file.write((char *)(&numColors), sizeof(int)); if (numColors > 0) { file.write((char *)(&(mesh.getColors())[0]), sizeof(ofFloatColor) * numColors); } int numIndices = mesh.getNumIndices(); file.write((char *)(&numIndices), sizeof(int)); if (numIndices > 0) { file.write((char *)(&(mesh.getIndices())[0]), sizeof(ofIndexType) * numIndices); } file.close(); }
vector<float> Model::generateTangents(ofMesh& mesh) { // Tangent generation adapted from algorithm at http://www.terathon.com/code/tangent.html auto vertices = mesh.getVertices(); auto normals = mesh.getNormals(); auto texcoords = mesh.getTexCoords(); auto triangles = mesh.getIndices(); vector<float> tangents(vertices.size()*4); vector<ofVec3f> tan1(vertices.size(), ofVec3f(0,0,0)); vector<ofVec3f> tan2(vertices.size(), ofVec3f(0,0,0)); for (unsigned int i = 0; i < triangles.size(); i += 3) { long i1 = triangles[i]; long i2 = triangles[i+1]; long i3 = triangles[i+2]; const ofVec3f& v1 = vertices[i1]; const ofVec3f& v2 = vertices[i2]; const ofVec3f& v3 = vertices[i3]; const ofVec2f& w1 = texcoords[i1]; const ofVec2f& w2 = texcoords[i2]; const ofVec2f& w3 = texcoords[i3]; float x1 = v2.x - v1.x; float x2 = v3.x - v1.x; float y1 = v2.y - v1.y; float y2 = v3.y - v1.y; float z1 = v2.z - v1.z; float z2 = v3.z - v1.z; float s1 = w2.x - w1.x; float s2 = w3.x - w1.x; float t1 = w2.y - w1.y; float t2 = w3.y - w1.y; float r = 1.0F / (s1 * t2 - s2 * t1); ofVec3f sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); ofVec3f tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); tan1[i1] += sdir; tan1[i2] += sdir; tan1[i3] += sdir; tan2[i1] += tdir; tan2[i2] += tdir; tan2[i3] += tdir; } for (unsigned int i = 0; i < vertices.size(); ++i) { ofVec3f& n = normals[i]; ofVec3f& t = tan1[i]; // Gram-Schmidt orthogonalize auto tangent = (t - n * n.dot(t)).normalize(); // Calculate handedness float w = (n.cross(t).dot(tan2[i]) < 0.0) ? -1.0 : 1.0; tangents[i*4] = tangent.x; tangents[i*4+1] = tangent.y; tangents[i*4+2] = tangent.z; tangents[i*4+3] = w; } return tangents; }
void CloudsVisualSystem3DModelLoader::smoothMesh( ofMesh& facetedMesh, ofMesh& targetMesh, int precision) { cout << "smoothing mesh" << endl; //get our vertex, uv and face info vector<ofVec3f>& v = facetedMesh.getVertices(); vector<ofVec2f>& uv = facetedMesh.getTexCoords(); vector<ofIndexType>& indices = facetedMesh.getIndices(); bool hasTC = facetedMesh.getNumTexCoords(); //use these to store our new mesh info map<string, unsigned int> mergeMap; vector<ofVec3f> smoothVertices; vector<ofVec3f> smoothNormals; vector<ofVec2f> smoothTexCoords; vector<ofIndexType> smoothIndices; //merge our vertices by pointing near by vertices to the same index for (int i=0; i<v.size(); i++) { mergeMap[ vec3ToString( v[i], precision ) ] = i; } //fill our smoothed vertex array with merged vertices & tex coords smoothVertices.resize( mergeMap.size() ); if(hasTC) smoothTexCoords.resize( mergeMap.size() ); int smoothVertexCount = 0; for (map<string, unsigned int>::iterator it = mergeMap.begin(); it != mergeMap.end(); it++) { smoothVertices[smoothVertexCount] = v[it->second]; if(hasTC) smoothTexCoords[smoothVertexCount] = uv[it->second]; it->second = smoothVertexCount;//store our new vertex index smoothVertexCount++; } //reconstruct our faces by reassigning their indices to the merged vertices smoothIndices.resize( indices.size() ); for (int i=0; i<indices.size(); i++) { //use our old vertex poisition to retrieve our new index smoothIndices[i] = mergeMap[ vec3ToString( v[ indices[i] ], precision ) ]; } //calculate our normals smoothNormals.resize( smoothVertices.size() ); ofVec3f n; for (int i=0; i<smoothIndices.size(); i+=3) { n = normalFrom3Points( smoothVertices[smoothIndices[i]], smoothVertices[smoothIndices[i+1]], smoothVertices[smoothIndices[i+2]] ); smoothNormals[smoothIndices[i]] += n; smoothNormals[smoothIndices[i+1]] += n; smoothNormals[smoothIndices[i+2]] += n; } for (int i=0; i<smoothNormals.size(); i++) { smoothNormals[i].normalize(); } //setup our smoothed mesh. this should still work if our targetMesh is our facetedMesh targetMesh.clear(); targetMesh.addVertices( smoothVertices ); targetMesh.addNormals( smoothNormals ); if(hasTC) targetMesh.addTexCoords( smoothTexCoords ); targetMesh.addIndices( smoothIndices ); }