void Mesh::loadOBJ(const char* filePath){ QFile file(filePath); if(!file.open(QIODevice::ReadOnly)){ return; } QTextStream data(&file); int usingMTL = 0; while(!data.atEnd()){ QString line = data.readLine(); if(line.size() == 0 || line[0] == '#') continue; QStringList arg = line.split(' '); if(arg.size() >= 4 && arg[0] == "v"){ vertices.push_back(vec3(arg[1].toFloat(), arg[2].toFloat(), arg[3].toFloat())); } else if(arg.size() >= 3 && arg[0] == "vt"){ uvs.push_back(vec3(arg[1].toFloat(), arg[2].toFloat(), 0)); } else if(arg.size() >= 4 && arg[0] == "vn"){ normals.push_back(vec3(arg[1].toFloat(), arg[2].toFloat(), arg[3].toFloat())); } else if(arg.size() >= 4 && arg[0] == "f"){ QVector<VerticesData> f; for(int i = 1;i<arg.size();++i){ VerticesData index; QStringList info = arg[i].split('/'); if(info.size() == 1){ index.v = info[0].toInt() - 1; index.vt = -1; index.vn = -1; } else if(info.size() == 2){ index.v = info[0].toInt() - 1; index.vt = info[1].toInt() - 1; index.vn = -1; } else if(info.size() == 3){ index.v = info[0].toInt() - 1; index.vt = info[1].toInt() - 1; index.vn = info[2].toInt() - 1; } f.push_back(index); } faces[usingMTL].push_back(f); } else if(arg.size() >= 2 && arg[0] == "mtllib"){ QString path; QStringList pathSplit = QString(filePath).split('/'); for(int i = 0;i < pathSplit.size()-1;++i) path += pathSplit[i] + '/'; loadMTL(arg[1], path); } else if(arg.size() >= 2 && arg[0] == "usemtl"){ usingMTL = materialName[arg[1]]; } } file.close(); update(); }
void renderObject::genBuffer(GLuint shader) { glDisableVertexAttribArray; std::vector< GLuint > indexes; std::vector < objBuffer > objB; std::string mtlFileName; std::string fileName = "mustang.obj"; bool res; res = loadOBJ(MESH_FOLDER + fileName, mtlFileName, objB, indexes); res = loadMTL(MESH_FOLDER + mtlFileName, mtl); res = loadTexture(MESH_FOLDER + mtl.texturePath, textureID); indexSize = indexes.size(); glGenBuffers(1, &vBuffer); glBindBuffer(GL_ARRAY_BUFFER, vBuffer); glBufferData(GL_ARRAY_BUFFER, objB.size() * sizeof(objBuffer), &objB[0], GL_DYNAMIC_DRAW); glGenBuffers(1, &indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexes.size() * sizeof(GLuint), &indexes[0], GL_DYNAMIC_DRAW); glGenVertexArrays(1, &vArray); glBindVertexArray(vArray); GLuint vertexPos = glGetAttribLocation(shader, "vertex_position"); glEnableVertexAttribArray(vertexPos); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(objBuffer), BUFFER_OFFSET(0)); GLuint textureNormal = glGetAttribLocation(shader, "texture_normal"); glEnableVertexAttribArray(textureNormal); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(objBuffer), BUFFER_OFFSET(3 * sizeof(GLfloat))); GLuint vertexNormal = glGetAttribLocation(shader, "vertex_normal"); glEnableVertexAttribArray(vertexNormal); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(objBuffer), BUFFER_OFFSET(5 * sizeof(GLfloat))); glFlush(); }
/*! \brief load the geometry defined in an OBJ/Wavefront file * \param filename is the path to the OJB file */ ObjReader::ObjReader(const char *filename) { std::ifstream ifs; // extract the path from the filename (used to read the material file) std::string path = getFilePath(filename); try { ifs.open(filename); if (ifs.fail()) throw std::runtime_error("can't open file " + std::string(filename)); // create a default material std::shared_ptr<Material> defaultMaterial(new Material("Default")); curMaterial = defaultMaterial; char line[MAX_LINE_LENGTH]; // line buffer while (ifs.peek() != EOF) // read each line until EOF is found { ifs.getline(line, sizeof(line), '\n'); const char* token = line + strspn(line, " \t"); // ignore space and tabs //printf("strncmp(token, vt, 2) --> %d\n", strncmp(token, "vt", 2)); if (token[0] == 0) continue; // line is empty, ignore // read a vertex if (token[0] == 'v' && isSep(token[1])) { v.push_back(getVec3f(token += 2)); continue; } // read a normal if (!strncmp(token, "vn", 2) && isSep(token[2])) { vn.push_back(getVec3f(token += 3)); continue; } // read a texture coordinates if (!strncmp(token, "vt", 2) && isSep(token[2])) { vt.push_back(getVec2f(token += 3)); continue; } //if (!strncmp(token, "vt", 2) && isSep(token[2])) { printf("vt: %.3f\n", getVec2f(token += 3).x); continue; } // read a face if (token[0] == 'f' && isSep(token[1])) { parseSep(token += 1); std::vector<Vertex> face; while (token[0]) { face.push_back(getInt3(token)); parseSepOpt(token); } curGroup.push_back(face); continue; } /*! use material */ if (!strncmp(token, "usemtl", 6) && isSep(token[6])) { flushFaceGroup(); std::string name(parseSep(token += 6)); if (materials.find(name) == materials.end()) curMaterial = defaultMaterial; else curMaterial = materials[name]; continue; } /* load material library */ if (!strncmp(token, "mtllib", 6) && isSep(token[6])) { loadMTL(path + "/" + std::string(parseSep(token += 6))); continue; } } } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } flushFaceGroup(); // flush the last loaded object ifs.close(); }
OBJLoader::OBJLoader(const FileName &fileName, const bool subdivMode) : path(fileName.path()), group(new SceneGraph::GroupNode), subdivMode(subdivMode) { /* open file */ std::ifstream cin; cin.open(fileName.c_str()); if (!cin.is_open()) { THROW_RUNTIME_ERROR("cannot open " + fileName.str()); return; } /* generate default material */ Material objmtl; new (&objmtl) OBJMaterial; Ref<SceneGraph::MaterialNode> defaultMaterial = new SceneGraph::MaterialNode(objmtl); curMaterial = defaultMaterial; char line[10000]; memset(line, 0, sizeof(line)); while (cin.peek() != -1) { /* load next multiline */ char* pline = line; while (true) { cin.getline(pline, sizeof(line) - (pline - line) - 16, '\n'); ssize_t last = strlen(pline) - 1; if (last < 0 || pline[last] != '\\') break; pline += last; *pline++ = ' '; } const char* token = trimEnd(line + strspn(line, " \t")); if (token[0] == 0) continue; /*! parse position */ if (token[0] == 'v' && isSep(token[1])) { v.push_back(getVec3f(token += 2)); continue; } /* parse normal */ if (token[0] == 'v' && token[1] == 'n' && isSep(token[2])) { vn.push_back(getVec3f(token += 3)); continue; } /* parse texcoord */ if (token[0] == 'v' && token[1] == 't' && isSep(token[2])) { vt.push_back(getVec2f(token += 3)); continue; } /*! parse face */ if (token[0] == 'f' && isSep(token[1])) { parseSep(token += 1); std::vector<Vertex> face; while (token[0]) { Vertex vtx = getInt3(token); face.push_back(vtx); parseSepOpt(token); } curGroup.push_back(face); continue; } /*! parse edge crease */ if (token[0] == 'e' && token[1] == 'c' && isSep(token[2])) { parseSep(token += 2); float w = getFloat(token); parseSepOpt(token); int a = fix_v(getInt(token)); parseSepOpt(token); int b = fix_v(getInt(token)); parseSepOpt(token); ec.push_back(Crease(w, a, b)); continue; } /*! use material */ if (!strncmp(token, "usemtl", 6) && isSep(token[6])) { flushFaceGroup(); std::string name(parseSep(token += 6)); if (material.find(name) == material.end()) curMaterial = defaultMaterial; else curMaterial = material[name]; continue; } /* load material library */ if (!strncmp(token, "mtllib", 6) && isSep(token[6])) { loadMTL(path + std::string(parseSep(token += 6))); continue; } // ignore unknown stuff } flushFaceGroup(); cin.close(); }
nMeshInstance *nObjFileLoader::loadObjMesh(string name, string object, double scale, nMeshInstance *inst) { if(!isupper(name[0]) && !(name.substr(1, 3) == "/:" || name.substr(1, 3) == "\\:")) name = nGine::instance()->appPath() + name; nTimer timer; timer.start(); ifstream file(name.c_str(), ios::in); if(!file) { nGine::instance()->getLogger()->addDebugLog("\nUnable to open " + name); return 0; } nMeshInstance *dp = inst; if(!dp) dp = new nMeshInstance; bool cull = false; string line; unsigned int totalVertexCount = 0; unsigned int triangleCount = 0; while(getline(file, line)) if(line.substr(0, 1) == "o") cull = (line.substr(2) != object && object.size()); else if(line.substr(0, 2) == "v ") totalVertexCount++; else if(line.substr(0, 1) == "f" && !cull) triangleCount++; file.close(); file.open(name.c_str(), ios::in); unsigned int triangles = 0; nIndexedTriangle *indexedTriangles = new nIndexedTriangle[triangleCount]; vector<vector<unsigned int> > index; vector<nVertex> vertices; vector<nVec3> normals; vector<nVec2> coords; vector<nMaterial *> materials; string obj; nMaterial *mat = 0; bool smooth = false; unsigned int vertexCount = 0; unsigned int li = 0; index.resize(totalVertexCount); //int faceParseType = 0; // 0 = unknown, 1 = position only, 2 = position + normal, 3 = pos + norm + tex while(getline(file, line)) { if(line.substr(0, 2) == "vt") { nVec2 c; sscanf(&line[0], "vt %lf %lf", &c.x, &c.y); coords.push_back(c); } else if(line.substr(0, 2) == "vn") { nVec3 n; sscanf(&line[0], "vn %lf %lf %lf", &n.x, &n.y, &n.z); normals.push_back(n); } else if(line.substr(0, 2) == "v ") { nVec3 v; sscanf(&line[0], "v %lf %lf %lf", &v.x, &v.y, &v.z); index[vertexCount].push_back(vertices.size()); vertices.push_back(nVertex(v * scale)); vertexCount++; } } //cout<<" ["<<timer.elapsed()<<"]"; file.close(); file.open(name.c_str(), ios::in); while(getline(file, line)) { li++; if(line.substr(0, 1) == "o") { bool culled = cull; obj = line.substr(2); cull = (obj != object && object.size()); if(cull && !culled) break; } else if(line.substr(0, 6) == "mtllib") { string fileName; unsigned int backslash = name.find_last_of('\\'); unsigned int slash = name.find_last_of('/'); if(backslash != string::npos && (backslash > slash || slash == string::npos)) fileName = name.substr(0, name.find_last_of('\\')) + "\\" + line.substr(7); else if(slash != string::npos) fileName = name.substr(0, name.find_last_of('/')) + "/" + line.substr(7); else fileName = line.substr(7); materials = loadMTL(fileName); } else if(line.substr(0, 6) == "usemtl") { mat = materials[0]; for(double i = 0; i != materials.size(); i++) if(materials[i]->getName() == line.substr(7)) { mat = materials[i]; break; } } else if(line.substr(0, 1) == "s") { smooth = (line != "s off"); } else if(line.substr(0, 1) == "f" && !cull) { if(line.find("//") != string::npos) { unsigned int v[6]; sscanf(&line[0], "f %d//%d %d//%d %d//%d", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5]); bool exists[3] = {false, false, false}; nIndexedTriangle tr; tr.material = mat; for(unsigned int j = 0; j != 3; j++) for(unsigned int i = 0; i != index[v[2 * j] - 1].size(); i++) if(vertices[index[v[2 * j] - 1][i]].normal.isNull() || vertices[index[v[2 * j] - 1][i]].normal == normals[v[2 * j + 1] - 1]) { tr.v[j] = index[v[2 * j] - 1][i]; vertices[index[v[2 * j] - 1][i]].normal = normals[v[2 * j + 1] - 1]; exists[j] = true; } for(unsigned int j = 0; j != 3; j++) if(!exists[j]) { index[v[2 * j] - 1].push_back(vertices.size()); tr.v[j] = vertices.size(); vertices.push_back(nVertex(vertices[v[2 * j] - 1].position, normals[v[2 * j + 1] - 1])); } indexedTriangles[triangles] = tr; triangles++; } else if(line.find("/") != string::npos) { unsigned int v[9]; sscanf(&line[0], "f %d/%d/%d %d/%d/%d %d/%d/%d", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8]); bool exists[3] = {false, false, false}; nIndexedTriangle tr; tr.material = mat; for(unsigned int j = 0; j != 3; j++) for(unsigned int i = 0; i != index[v[3 * j] - 1].size(); i++) #ifdef N_MULTI_TEX_COORD if((vertices[index[v[3 * j] - 1][i]].normal.isNull() || vertices[index[v[3 * j] - 1][i]].normal == normals[v[3 * j + 2] - 1]) && (isinf(vertices[index[v[3 * j] - 1][i]].tex[0].x) || vertices[index[v[3 * j] - 1][i]].tex[0] == coords[v[3 * j + 1] - 1])) #else if((vertices[index[v[3 * j] - 1][i]].normal.isNull() || vertices[index[v[3 * j] - 1][i]].normal == normals[v[3 * j + 2] - 1]) && (isinf(vertices[index[v[3 * j] - 1][i]].coords.x) || vertices[index[v[3 * j] - 1][i]].coords == coords[v[3 * j + 1] - 1])) #endif { tr.v[j] = index[v[3 * j] - 1][i]; vertices[index[v[3 * j] - 1][i]].normal = normals[v[3 * j + 2] - 1]; #ifdef N_MULTI_TEX_COORD vertices[index[v[3 * j] - 1][i]].tex[0] = coords[v[3 * j + 1] - 1]; #else vertices[index[v[3 * j] - 1][i]].coords = coords[v[3 * j + 1] - 1]; #endif exists[j] = true; } for(unsigned int j = 0; j != 3; j++) if(!exists[j]) { index[v[3 * j] - 1].push_back(vertices.size()); tr.v[j] = vertices.size(); vertices.push_back(nVertex(vertices[v[3 * j] - 1].position, normals[v[3 * j + 2] - 1], coords[v[3 * j + 1] - 1])); } indexedTriangles[triangles] = tr; triangles++; } else { unsigned int v1[3]; sscanf(&line[0], "f %d %d %d", &v1[0], &v1[1], &v1[2]); indexedTriangles[triangles] = nIndexedTriangle(v1[0] - 1, v1[1] - 1, v1[2] - 1, mat); triangles++; } } } for(unsigned int i = 0; i != vertices.size(); i++) dp->addVertex(vertices[i]); for(unsigned int i = 0; i != triangles; i++) dp->addTriangle(indexedTriangles[i]); delete indexedTriangles; for(unsigned int i = 0; i != index.size(); i++) index[i].clear(); index.clear(); vertices.clear(); normals.clear(); coords.clear(); materials.clear(); if(object.size()) dp->computeUnused(); cout<<" ["<<timer.reset() * 1000<<"ms]"; dp->build(nMeshInstance::Mesh); cout<<" ["<<timer.elapsed() * 1000<<"ms]"<<endl; return dp; /*string line; while(getline(file, line)) if(line.substr(0, 1) == "o") cull = (line.substr(2) != object && object.size()); else if(line.substr(0, 2) == "v ") dp->setVertexCount(dp->getVertexCount() + 1); else if(line.substr(0, 1) == "f" && !cull) dp->setTriangleCount(dp->getTriangleCount() + 1); file.close(); file.open(name.c_str(), ios::in); unsigned int triangles = 0; dp->triangles = new nIndexedTriangle[dp->getTriangleCount()]; vector<vector<unsigned int> > index; vector<nVertex> vertices; vector<nVec3> normals; vector<nVec2> coords; vector<nMaterial *> materials; string obj; nMaterial *mat = 0; bool smooth = false; unsigned int vertexCount = 0; unsigned int li = 0; index.resize(dp->getVertexCount()); //int faceParseType = 0; // 0 = unknown, 1 = position only, 2 = position + normal, 3 = pos + norm + tex while(getline(file, line)) { if(line.substr(0, 2) == "vt") { nVec2 c; sscanf(&line[0], "vt %lf %lf", &c.x, &c.y); coords.push_back(c); } else if(line.substr(0, 2) == "vn") { nVec3 n; sscanf(&line[0], "vn %lf %lf %lf", &n.x, &n.y, &n.z); normals.push_back(n); } else if(line.substr(0, 2) == "v ") { nVec3 v; sscanf(&line[0], "v %lf %lf %lf", &v.x, &v.y, &v.z); index[vertexCount].push_back(vertices.size()); vertices.push_back(nVertex(v * scale)); vertexCount++; } } //cout<<" ["<<timer.elapsed()<<"]"; file.close(); file.open(name.c_str(), ios::in); while(getline(file, line)) { li++; if(line.substr(0, 1) == "o") { bool culled = cull; obj = line.substr(2); cull = (obj != object && object.size()); if(cull && !culled) break; } else if(line.substr(0, 6) == "mtllib") { string fileName; unsigned int backslash = name.find_last_of('\\'); unsigned int slash = name.find_last_of('/'); if(backslash != string::npos && (backslash > slash || slash == string::npos)) fileName = name.substr(0, name.find_last_of('\\')) + "\\" + line.substr(7); else if(slash != string::npos) fileName = name.substr(0, name.find_last_of('/')) + "/" + line.substr(7); else fileName = line.substr(7); materials = loadMTL(fileName); } else if(line.substr(0, 6) == "usemtl") { mat = materials[0]; for(double i = 0; i != materials.size(); i++) if(materials[i]->getName() == line.substr(7)) { mat = materials[i]; break; } } else if(line.substr(0, 1) == "s") { smooth = (line != "s off"); } else if(line.substr(0, 1) == "f" && !cull) { if(line.find("//") != string::npos) { unsigned int v[6]; sscanf(&line[0], "f %d//%d %d//%d %d//%d", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5]); bool exists[3] = {false, false, false}; nIndexedTriangle tr; tr.material = mat; for(unsigned int j = 0; j != 3; j++) for(unsigned int i = 0; i != index[v[2 * j] - 1].size(); i++) if(vertices[index[v[2 * j] - 1][i]].normal.isNull() || vertices[index[v[2 * j] - 1][i]].normal == normals[v[2 * j + 1] - 1]) { tr.v[j] = index[v[2 * j] - 1][i]; vertices[index[v[2 * j] - 1][i]].normal = normals[v[2 * j + 1] - 1]; exists[j] = true; } for(unsigned int j = 0; j != 3; j++) if(!exists[j]) { index[v[2 * j] - 1].push_back(vertices.size()); tr.v[j] = vertices.size(); vertices.push_back(nVertex(vertices[v[2 * j] - 1].position, normals[v[2 * j + 1] - 1])); } dp->triangles[triangles] = tr; triangles++; } else if(line.find("/") != string::npos) { unsigned int v[9]; sscanf(&line[0], "f %d/%d/%d %d/%d/%d %d/%d/%d", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8]); bool exists[3] = {false, false, false}; nIndexedTriangle tr; tr.material = mat; for(unsigned int j = 0; j != 3; j++) for(unsigned int i = 0; i != index[v[3 * j] - 1].size(); i++) #ifdef N_MULTI_TEX_COORD if((vertices[index[v[3 * j] - 1][i]].normal.isNull() || vertices[index[v[3 * j] - 1][i]].normal == normals[v[3 * j + 2] - 1]) && (isinf(vertices[index[v[3 * j] - 1][i]].tex[0].x) || vertices[index[v[3 * j] - 1][i]].tex[0] == coords[v[3 * j + 1] - 1])) #else if((vertices[index[v[3 * j] - 1][i]].normal.isNull() || vertices[index[v[3 * j] - 1][i]].normal == normals[v[3 * j + 2] - 1]) && (isinf(vertices[index[v[3 * j] - 1][i]].coords.x) || vertices[index[v[3 * j] - 1][i]].coords == coords[v[3 * j + 1] - 1])) #endif { tr.v[j] = index[v[3 * j] - 1][i]; vertices[index[v[3 * j] - 1][i]].normal = normals[v[3 * j + 2] - 1]; #ifdef N_MULTI_TEX_COORD vertices[index[v[3 * j] - 1][i]].tex[0] = coords[v[3 * j + 1] - 1]; #else vertices[index[v[3 * j] - 1][i]].coords = coords[v[3 * j + 1] - 1]; #endif exists[j] = true; } for(unsigned int j = 0; j != 3; j++) if(!exists[j]) { index[v[3 * j] - 1].push_back(vertices.size()); tr.v[j] = vertices.size(); vertices.push_back(nVertex(vertices[v[3 * j] - 1].position, normals[v[3 * j + 2] - 1], coords[v[3 * j + 1] - 1])); } dp->triangles[triangles] = tr; triangles++; } else { unsigned int v1[3]; sscanf(&line[0], "f %d %d %d", &v1[0], &v1[1], &v1[2]); dp->triangles[triangles] = nIndexedTriangle(v1[0] - 1, v1[1] - 1, v1[2] - 1, mat); triangles++; } } } dp->setVertexCount(vertices.size()); dp->vertices = new nVertex[dp->getVertexCount()]; for(unsigned int i = 0; i != dp->getVertexCount(); i++) dp->vertices[i] = vertices[i]; for(unsigned int i = 0; i != index.size(); i++) index[i].clear(); index.clear(); vertices.clear(); normals.clear(); coords.clear(); materials.clear(); if(object.size()) dp->computeUnused(); cout<<" ["<<timer.reset() * 1000<<"ms]"; dp->build(nMeshInstance::BuildMesh); cout<<" ["<<timer.elapsed() * 1000<<"ms]"<<endl; return dp;*/ }
bool ObjModel::loadOBJ(string filePath, string objFile){ this->filePath = filePath; this->objFile = objFile; cout << "Loading OBJ file " << objFile << endl; vector<unsigned int> vertexIndices, textureIndices, normalIndices; vector<vec3> temp_vertices; vector<vec2> temp_textures; vector<vec3> temp_normals; ObjGroup temp_group; string filename = filePath + "/" + objFile; FILE* file = fopen(filename.c_str(), "r"); if( file == NULL ){ printf("Impossible to open the OBJ file !!!\n"); return false; } while(true){ char lineHeader[128]; // read the first word of the line int res = fscanf(file, "%s", lineHeader); if (res == EOF) break; // EOF = End Of File. Quit the loop. // else : parse lineHeader if (strcmp(lineHeader, "mtllib") == 0 ){ char ch[128]; fscanf(file, "%s", ch); mtlFile = ch; loadMTL(); } else if (strcmp(lineHeader, "g") == 0 ){ if (!temp_group.name.empty()){ groups.push_back(temp_group); } temp_group.clear(); char chname[128]; fscanf(file, "%s", chname); temp_group.name = chname; } else if (strcmp(lineHeader, "usemtl") == 0 ){ if (!temp_group.quads.empty() || !temp_group.triangles.empty()){ groups.push_back(temp_group); temp_group.clear(); } char chmtl[128]; fscanf(file, "%s", chmtl); temp_group.material = chmtl; } else if (strcmp(lineHeader, "v") == 0){ vec3 vertex; fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z ); temp_vertices.push_back(vertex); } else if (strcmp(lineHeader, "vt") == 0 ){ vec2 uv; fscanf(file, "%f %f\n", &uv.x, &uv.y ); // uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders. temp_textures.push_back(uv); } else if (strcmp(lineHeader, "vn") == 0 ){ vec3 normal; fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z ); temp_normals.push_back(normal); } else if (strcmp(lineHeader, "f") == 0 ){ bool isTriangle = true; unsigned int vertexIndex[4], textureIndex[4], normalIndex[4]; for (int k = 0; k < 4; k++){ char c_s[100]; fscanf(file, "%s", c_s); string s(c_s); if (k == 3){ if (s[0] >= '0' && s[0] <= '9'){ isTriangle = false; } else{ fseek(file, -s.size(), SEEK_CUR); break; } } int fpos = s.find_first_of('/'); if (fpos == string::npos){ vertexIndex[k] = atoi(s.c_str()); textureIndex[k] = 0; normalIndex[k] = 0; continue; } vertexIndex[k] = atoi(s.substr(0, fpos).c_str()); int lpos = s.find_last_of('/'); if (fpos == lpos){ textureIndex[k] = atoi(s.substr(lpos + 1, s.size() - lpos - 1).c_str()); normalIndex[k] = 0; } else if (lpos == fpos + 1){ textureIndex[k] = 0; normalIndex[k] = atoi(s.substr(lpos + 1, s.size() - lpos - 1).c_str()); } else{ textureIndex[k] = atoi(s.substr(fpos + 1, lpos - fpos - 1).c_str()); normalIndex[k] = atoi(s.substr(lpos + 1, s.size() - lpos - 1).c_str()); } } if (isTriangle){ ObjPoint point[3]; ObjTriangle triangle; for (int i = 0; i < 3; i++){ point[i].vertex.x = temp_vertices[vertexIndex[i] - 1].x; point[i].vertex.y = temp_vertices[vertexIndex[i] - 1].y; point[i].vertex.z = temp_vertices[vertexIndex[i] - 1].z; if (textureIndex[i] > 0){ point[i].texCoord.x = temp_textures[textureIndex[i] - 1].x; point[i].texCoord.y = temp_textures[textureIndex[i] - 1].y; } else{ point[i].texCoord.x = -100; point[i].texCoord.y = -100; } if (normalIndex[i] > 0){ point[i].normal.x = temp_normals[normalIndex[i] - 1].x; point[i].normal.y = temp_normals[normalIndex[i] - 1].y; point[i].normal.z = temp_normals[normalIndex[i] - 1].z; } else{ point[i].normal.x = -100; point[i].normal.y = -100; point[i].normal.z = -100; } triangle.points[i] = point[i]; } temp_group.triangles.push_back(triangle); } else{ ObjPoint point[4]; ObjQuad quad; for (int i = 0; i < 4; i++){ point[i].vertex.x = temp_vertices[vertexIndex[i] - 1].x; point[i].vertex.y = temp_vertices[vertexIndex[i] - 1].y; point[i].vertex.z = temp_vertices[vertexIndex[i] - 1].z; if (textureIndex[i] > 0){ point[i].texCoord.x = temp_textures[textureIndex[i] - 1].x; point[i].texCoord.y = temp_textures[textureIndex[i] - 1].y; } else{ point[i].texCoord.x = -1; point[i].texCoord.y = -1; } if (normalIndex[i] > 0){ point[i].normal.x = temp_normals[normalIndex[i] - 1].x; point[i].normal.y = temp_normals[normalIndex[i] - 1].y; point[i].normal.z = temp_normals[normalIndex[i] - 1].z; } else{ point[i].normal.x = -1; point[i].normal.y = -1; point[i].normal.z = -1; } quad.points[i] = point[i]; } temp_group.quads.push_back(quad); } } else{ // Probably a comment, eat up the rest of the line char stupidBuffer[1000]; fgets(stupidBuffer, 1000, file); } } if (!temp_group.triangles.empty() || !temp_group.quads.empty()){ groups.push_back(temp_group); } if (groups.empty()){ temp_group.name = "default"; groups.push_back(temp_group); } setArea(); return true; }
int readOBJ(struct OBJ_Model * obj) { if (obj->filename == 0 ) { fprintf(stderr,"readOBJ called with a null filename , cannot continue \n"); return 0; } /* Read the .obj model from file FILENAME */ /* All faces are converted to be triangles */ FILE *file=0; char buf[128]; char buf1[128]; unsigned int wrongDecimalSeperatorBug=0; long unsigned int numvertices; /* number of vertices in model */ long unsigned int numnormals; /* number of normals in model */ long unsigned int numcolors; long unsigned int numtexs; /* number of normals in texture coordintaes */ long unsigned int numfaces; /* number of faces in model */ long unsigned int numgroups; /* number of groups in model */ GLuint cur_group,material, mat; long unsigned int v,n,t,i; int grp; fprintf(stderr,"TODO : proper string allocation here for filename %s \n",obj->filename); char fname[2*MAX_MODEL_PATHS+1]={0}; snprintf(fname,2*MAX_MODEL_PATHS,"%s/%s.obj",obj->directory , obj->filename); fprintf(stderr,"Opening File %s ..\n",fname); file=fopen(fname,"r"); if(file==0) { fprintf(stderr,"Could not open file %s for reading Object\n",fname); return 0; } // strcpy(name,filename); strcpy(obj->matLib,""); //Group Pass rewind(file); numgroups = 1; while(fscanf(file, "%s", buf) != EOF) { if(buf[0]=='g') numgroups++; else fgets(buf, sizeof(buf), file); // eat up rest of line } if(numgroups==0) { numgroups=1; } obj->groups = (Group*) malloc(sizeof(Group)* numgroups); if (obj->groups == 0) { fprintf(stderr,"Could not make enough space for %lu groups \n",numgroups); fclose(file); return 0; } obj->numGroups = 0; obj->numFaces =0; // 1st Pass rewind(file); numtexs = 0; numvertices = 0; numnormals = 0; numcolors = 0; numfaces = 0; cur_group = AddGroup(obj,"default"); obj->groups[0].material=0; while(fscanf(file, "%s", buf) != EOF) { if(strcmp(buf, "mtllib")==0) { fscanf(file, "%s", buf1); strcpy(obj->matLib, buf1); loadMTL(obj,obj->directory ,buf1); printf("loadmtl %s survived\n", obj->matLib); } switch(buf[0]) { case '#': fgets(buf, sizeof(buf), file); break; // comment eat up rest of line // v, vn, vt case 'v': switch(buf[1]) { case '\0': // vertex eat up rest of line fgets(buf, sizeof(buf), file); numvertices++; if (floatingPointCheck(buf,strlen(buf)) ) { ++wrongDecimalSeperatorBug; } if (countChar(buf,strlen(buf),' ',buf[1])==6) { numcolors++ ; } //meshlab extension for colors on obj files break; case 'n': // normal eat up rest of line fgets(buf, sizeof(buf), file); numnormals++; break; case 't': //texture coordinate eat up rest of line fgets(buf, sizeof(buf), file); numtexs ++; break; default: fprintf(stderr,"Unexpected characters ( \"%s\" ) while waiting for v, vn ,vt .\n", buf); return 0; break; } break; case 'm': fgets(buf, sizeof(buf), file); break; case 'u': fgets(buf, sizeof(buf), file); break;// eat up rest of line case 'g': //group eat up rest of line fgets(buf, sizeof(buf), file); sscanf(buf, "%s", buf); cur_group = AddGroup(obj,buf); break; case 'f': // face v =0; n = 0; t = 0; fscanf(file, "%s", buf); // can be one of %d, %d//%d, %d/%d, %d/%d/%d if (strstr(buf, "//")) { // v//n sscanf(buf, "%d//%d", &v, &n); fscanf(file, "%d//%d", &v, &n); fscanf(file, "%d//%d", &v, &n); obj->numFaces++; while(fscanf(file, "%d//%d", &v, &n) > 0) { obj->numFaces++; } } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { // v/t/n fscanf(file, "%d/%d/%d", &v, &t, &n); fscanf(file, "%d/%d/%d", &v, &t, &n); obj->numFaces++; while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { obj->numFaces++; } } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { // v/t fscanf(file, "%d/%d", &v, &t); fscanf(file, "%d/%d", &v, &t); obj->numFaces++; while(fscanf(file, "%d/%d", &v, &t) > 0) { obj->numFaces++; } } else { // v fscanf(file, "%d", &v); fscanf(file, "%d", &v); obj->numFaces++; while(fscanf(file, "%d", &v) > 0) { obj->numFaces++; } } break; //end of face case default: fgets(buf, sizeof(buf), file); break; // eat up rest of line } } // set the stats in the model structure obj->numVertices = numvertices; obj->numNormals = numnormals; obj->numTexs = numtexs; obj->numColors = numcolors; printf("Vertices : %ld\n",obj->numVertices); printf("Normals : %ld\n",obj->numNormals); printf("Faces : %ld\n",obj->numFaces); printf("Groups : %ld\n",obj->numGroups); printf("Texes : %ld\n",obj->numTexs); printf("Colors : %ld\n",obj->numColors); if (wrongDecimalSeperatorBug) { fprintf(stderr,RED "! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !\n"); fprintf(stderr,RED "\n\n\n\nThis OBJ file has a wrong seperator for floating point numbers \n"); fprintf(stderr," please use sed -i 's/,/./g' %s \n\n\n" NORMAL,obj->filename); fprintf(stderr,RED "! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !\n"); } for(i=0; i<obj->numGroups; i++) { obj->groups[i].numFaces=0; printf("%d\n", obj->groups[i].hasNormals);//0, 0 } // Allocating memory fprintf(stderr,"Allocating memory for faces\n"); obj->faceList = (Face*) malloc(sizeof(Face)*(obj->numFaces+2)); if (obj->faceList == 0) { fprintf(stderr,"Could not allocate enough memory for face struct\n"); } memset (obj->faceList,0,sizeof(Face)*(obj->numFaces+2)); fprintf(stderr,"Allocating memory for vertices\n"); obj->vertexList = (Vertex*) malloc(sizeof(Vertex)*(obj->numVertices+2)); if (obj->vertexList == 0) { fprintf(stderr,"Could not allocate enough memory for vertex struct\n"); } memset (obj->vertexList,0,sizeof(Vertex)*(obj->numVertices+2)); if(obj->numNormals!=0) { fprintf(stderr,"Allocating memory for normals\n"); obj->normalList=(Normal*)malloc(sizeof(Normal)*(obj->numNormals+2)); if (obj->normalList == 0) { fprintf(stderr,"Could not allocate enough memory for normal struct\n"); } memset (obj->normalList,0,sizeof(Normal)*(obj->numNormals+2)); } if(obj->numTexs!=0) { fprintf(stderr,"Allocating memory for textures\n"); obj->texList=(TexCoords*)malloc(sizeof(TexCoords)*(obj->numTexs+2)); if (obj->texList == 0) { fprintf(stderr,"Could not allocate enough memory for texture struct\n"); } memset (obj->texList,0,sizeof(TexCoords)*(obj->numTexs+2)); } if(obj->numColors!=0) { fprintf(stderr,"Allocating memory for colors\n"); obj->colorList=(RGBColors*)malloc(sizeof(RGBColors)*(obj->numColors+2)); if (obj->colorList == 0) { fprintf(stderr,"Could not allocate enough memory for colors struct\n"); } memset (obj->colorList,0,sizeof(RGBColors)*(obj->numColors+2)); } // Second Pass rewind(file); //These dont work if they become 0 :P obj->numVertices = 1; obj->numNormals = 1; obj->numTexs = 1; obj->numColors = 1; obj->customColor =( obj->numColors > 0 ); obj->numFaces = 0; material = 0; grp = 0; while(!feof(file)) { fscanf(file, "%s", buf); if(!strcmp(buf, "usemtl")) { fscanf(file, "%s", buf1); unsigned int foundMaterial; if ( FindMaterial( obj, buf1 , &foundMaterial) ) { mat = foundMaterial; obj->groups[grp].material = mat; strcpy(obj->matLib, buf1); printf("loadmtl %s\n", obj->matLib); } } switch(buf[0]) { case '#': fgets(buf, sizeof(buf), file); break; // comment eat up rest of line case 'v': // v, vn, vt switch(buf[1]) { case '\0': // vertex if ( obj->customColor ) { fscanf(file, "%f %f %f %f %f %f", &obj->vertexList[obj->numVertices].x, &obj->vertexList[obj->numVertices].y, &obj->vertexList[obj->numVertices].z, &obj->colorList[obj->numColors].r, &obj->colorList[obj->numColors].g, &obj->colorList[obj->numColors].b ); obj->numVertices++; obj->numColors++; } else { fscanf(file, "%f %f %f", &obj->vertexList[obj->numVertices].x, &obj->vertexList[obj->numVertices].y, &obj->vertexList[obj->numVertices].z); obj->numVertices++; } break; case 'n': // normal fscanf(file, "%f %f %f", &obj->normalList[obj->numNormals].n1, &obj->normalList[obj->numNormals].n2, &obj->normalList[obj->numNormals].n3); obj->numNormals++; break; case 't': // normal fscanf(file, "%f %f", &obj->texList[obj->numTexs].u, &obj->texList[obj->numTexs].v); obj->numTexs++; break; } break; case 'u': fgets(buf, sizeof(buf), file); break; // eat up rest of line case 'g': // group eat up rest of line fgets(buf, sizeof(buf), file); sscanf(buf, "%s", buf); grp = FindGroup(obj,buf); obj->groups[grp].material = material; break; case 'f': //face v = 0; n = 0; t = 0; fscanf(file, "%s", buf); // can be one of %d, %d//%d, %d/%d, %d/%d/%d if (strstr(buf, "//")) { // v//n sscanf(buf, "%d//%d", &v, &n); obj->faceList[obj->numFaces].v[0] = v; obj->faceList[obj->numFaces].n[0] = n; fscanf(file, "%d//%d", &v, &n); obj->faceList[obj->numFaces].v[1] = v; obj->faceList[obj->numFaces].n[1] = n; fscanf(file, "%d//%d", &v, &n); obj->faceList[obj->numFaces].v[2] = v; obj->faceList[obj->numFaces].n[2] = n; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; obj->groups[grp].hasNormals = 1; obj->groups[grp].hasTex = 0; while(fscanf(file, "%d//%d", &v, &n) > 0) { obj->faceList[obj->numFaces].v[0] = obj->faceList[obj->numFaces-1].v[0]; obj->faceList[obj->numFaces].n[0] = obj->faceList[obj->numFaces-1].n[0]; obj->faceList[obj->numFaces].v[1] = obj->faceList[obj->numFaces-1].v[2]; obj->faceList[obj->numFaces].n[1] = obj->faceList[obj->numFaces-1].n[2]; obj->faceList[obj->numFaces].v[2] = v; obj->faceList[obj->numFaces].n[2] = n; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; } } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { // v/t/n obj->faceList[obj->numFaces].v[0] = v; obj->faceList[obj->numFaces].n[0] = n; obj->faceList[obj->numFaces].t[0] = t; fscanf(file, "%d/%d/%d", &v, &t, &n); obj->faceList[obj->numFaces].v[1] = v; obj->faceList[obj->numFaces].n[1] = n; obj->faceList[obj->numFaces].t[1] = t; fscanf(file, "%d/%d/%d", &v, &t, &n); obj->faceList[obj->numFaces].v[2] = v; obj->faceList[obj->numFaces].n[2] = n; obj->faceList[obj->numFaces].t[2] = t; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; obj->groups[grp].hasNormals = 1; obj->groups[grp].hasTex = 1; while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { obj->faceList[obj->numFaces].v[0] = obj->faceList[obj->numFaces-1].v[0]; obj->faceList[obj->numFaces].n[0] = obj->faceList[obj->numFaces-1].n[0]; obj->faceList[obj->numFaces].t[0] = obj->faceList[obj->numFaces-1].t[0]; obj->faceList[obj->numFaces].v[1] = obj->faceList[obj->numFaces-1].v[2]; obj->faceList[obj->numFaces].n[1] = obj->faceList[obj->numFaces-1].n[2]; obj->faceList[obj->numFaces].t[1] = obj->faceList[obj->numFaces-1].t[2]; obj->faceList[obj->numFaces].v[2] = v; obj->faceList[obj->numFaces].n[2] = n; obj->faceList[obj->numFaces].t[2] = t; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; } } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { // v/t obj->groups[grp].hasTex = 1; obj->faceList[obj->numFaces].v[0] = v; obj->faceList[obj->numFaces].t[0] = t; fscanf(file, "%d/%d", &v, &t); obj->faceList[obj->numFaces].v[1] = v; obj->faceList[obj->numFaces].t[1] = t; fscanf(file, "%d/%d", &v, &t); obj->faceList[obj->numFaces].v[2] = v; obj->faceList[obj->numFaces].t[2] = t; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; while(fscanf(file, "%d/%d", &v, &t) > 0) { obj->faceList[obj->numFaces].v[0] = obj->faceList[obj->numFaces-1].v[0]; obj->faceList[obj->numFaces].t[0] = obj->faceList[obj->numFaces-1].t[0]; obj->faceList[obj->numFaces].v[1] = obj->faceList[obj->numFaces-1].v[2]; obj->faceList[obj->numFaces].t[1] = obj->faceList[obj->numFaces-1].t[2]; obj->faceList[obj->numFaces].v[2] = v; obj->faceList[obj->numFaces].t[2] = t; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; }//while } else { // v sscanf(buf, "%d", &v); obj->faceList[obj->numFaces].v[0] = v; fscanf(file, "%d", &v); obj->faceList[obj->numFaces].v[1] = v; fscanf(file, "%d", &v); obj->faceList[obj->numFaces].v[2] = v; obj->groups[grp].hasNormals = 0; obj->groups[grp].hasTex = 0; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; while(fscanf(file, "%d", &v) == 1) { obj->faceList[obj->numFaces].v[0] = obj->faceList[obj->numFaces-1].v[0]; obj->faceList[obj->numFaces].v[1] = obj->faceList[obj->numFaces-1].v[2]; obj->faceList[obj->numFaces].v[2] = v; AddFacetoG(&obj->groups[grp],obj->numFaces); obj->numFaces++; } } break; default: fgets(buf, sizeof(buf), file); break; // eat up rest of line } } fclose(file); printf("Model has %ld faces %u colors \n",obj->numFaces, obj->numColors); for(i=0; i<obj->numGroups; i++) { // fprintf(stderr,"Group %s has %ld faces and material %s, \t \n",obj->groups[i].name,obj->groups[i].numFaces,obj->matList[obj->groups[i].material].name); } #if CALCULATE_3D_BOUNDING_BOX calculateOBJBBox(obj); #endif // CALCULATE_3D_BOUNDING_BOX return 1; }
void ArticulatedModel::initOBJ(const std::string& filename, const Preprocess& preprocess) { Stopwatch loadTimer; TextInput::Settings set; set.cppBlockComments = false; set.cppLineComments = false; set.otherCommentCharacter = '#'; set.generateNewlineTokens = true; // Notes on OBJ file format. See also: // // - http://www.martinreddy.net/gfx/3d/OBJ.spec // - http://en.wikipedia.org/wiki/Obj // - http://www.royriggs.com/obj.html // // OBJ indexing is 1-based. // Line breaks are significant. // The first token on a line indicates the contents of the line. // // Faces contain separate indices for normals and texcoords. // We load the raw vertices and then form our own optimized // gl indices from them. // // Negative indices are relative to the last coordinate seen. // Raw arrays with independent indexing, as imported from the file Array<Vector3> rawVertex; Array<Vector3> rawNormal; Array<Vector2> rawTexCoord; // part.geometry.vertexArray[i] = rawVertex[cookVertex[i]]; Array<int> cookVertex; Array<int> cookNormal; Array<int> cookTexCoord; // Put everything into a single part // Convert to a Part Part& part = partArray.next(); part.cframe = CoordinateFrame(); part.name = "root"; part.parent = -1; // v,t,n repeated for each vertex Array<int> faceTempIndex; // Count of errors from mismatched texcoord and vertex int texCoordChanged = 0; int normalChanged = 0; Table<std::string, Material::Ref> materialLibrary; Table<std::string, TriListSpec*> groupTable; TriListSpec* currentTriList = NULL; int numTris = 0; const Matrix3 normalXform = preprocess.xform.upper3x3().transpose().inverse(); const std::string& basePath = FilePath::parent(FileSystem::resolve(filename)); { TextInput ti(filename, set); while (ti.hasMore()) { // Consume comments/newlines while (ti.hasMore() && (ti.peek().type() == Token::NEWLINE)) { // Consume the newline ti.read(); } if (! ti.hasMore()) { break; } // Process one line const std::string& cmd = ti.readSymbol(); if (cmd == "mtllib") { // Specify material library const std::string& mtlFilename = ti.readUntilNewlineAsString(); loadMTL(FilePath::concat(basePath, mtlFilename), materialLibrary, preprocess); } else if (cmd == "g") { // New trilist const std::string& name = ti.readUntilNewlineAsString(); if (! groupTable.containsKey(name)) { currentTriList = new TriListSpec(); currentTriList->name = name; groupTable.set(name, currentTriList); } else { currentTriList = groupTable[name]; } } else if (cmd == "usemtl") { if (currentTriList) { currentTriList->materialName = ti.readUntilNewlineAsString(); } } else if (cmd == "v") { rawVertex.append(readVertex(ti, preprocess.xform)); } else if (cmd == "vt") { // Texcoord Vector2& t = rawTexCoord.next(); t.x = ti.readNumber(); t.y = 1.0f - ti.readNumber(); } else if (cmd == "vn") { // Normal rawNormal.append(readNormal(ti, normalXform)); } else if ((cmd == "f") && currentTriList) { // Face // Read each vertex while (ti.hasMore() && (ti.peek().type() != Token::NEWLINE)) { // Read one 3-part index int v = ti.readNumber(); if (v < 0) { v = rawVertex.size() + 1 + v; } int n = 0; int t = 0; if (ti.peek().type() == Token::SYMBOL) { ti.readSymbol("/"); if (ti.peek().type() == Token::NUMBER) { t = ti.readNumber(); if (t < 0) { t = rawTexCoord.size() + 1 + t; } } if (ti.peek().type() == Token::SYMBOL) { ti.readSymbol("/"); if (ti.peek().type() == Token::NUMBER) { n = ti.readNumber(); if (n < 0) { n = rawNormal.size() + 1 + n; } } } } // Switch to zero-based indexing --v; --n; --t; faceTempIndex.append(v, t, n); } alwaysAssertM(faceTempIndex.size() >= 3*3, "Face with fewer than three vertices in model."); numTris += (faceTempIndex.size()/3) - 2; // The faceTempIndex is now a triangle fan. Convert it to a triangle list and use unique vertices for (int i = 2; i < faceTempIndex.size()/3; ++i) { // Always start with vertex 0 cookVertex.append(faceTempIndex[0]); cookTexCoord.append(faceTempIndex[1]); cookNormal.append(faceTempIndex[2]); // The vertex just before the one we're adding int j = (i - 1) * 3; cookVertex.append(faceTempIndex[j]); cookTexCoord.append(faceTempIndex[j+1]); cookNormal.append(faceTempIndex[j+2]); // The vertex we're adding j = i * 3; cookVertex.append(faceTempIndex[j]); cookTexCoord.append(faceTempIndex[j+1]); cookNormal.append(faceTempIndex[j+2]); // Update the index array to contain the three vertices we just added currentTriList->cpuIndex.append(cookVertex.size() - 3, cookVertex.size() - 2, cookVertex.size() - 1); } faceTempIndex.fastClear(); } // Read until the end of the line while (ti.hasMore() && (ti.read().type() != Token::NEWLINE)); } } debugPrintf("Creating TriLists\n"); // Copy geometry const int N = cookVertex.size(); part.geometry.vertexArray.resize(N); for (int i = 0; i < N; ++i) { part.geometry.vertexArray[i] = rawVertex[cookVertex[i]]; } // Optional normals if (rawNormal.size() > 0) { part.geometry.normalArray.resize(N); for (int i = 0; i < N; ++i) { part.geometry.normalArray[i] = rawNormal[cookNormal[i]]; } } // Optional texcoords if (rawTexCoord.size() > 0) { part.texCoordArray.resize(N); for (int i = 0; i < N; ++i) { part.texCoordArray[i] = rawTexCoord[cookTexCoord[i]]; } } // Create trilists for (Table<std::string, TriListSpec*>::Iterator it = groupTable.begin(); it.hasMore(); ++it) { TriListSpec* s = it->value; Material::Ref material; if (materialLibrary.containsKey(s->materialName)) { material = materialLibrary[s->materialName]; } else { material = Material::createDiffuse(Color3::white() * 0.8f); debugPrintf("Warning: unrecognized material: %s\n", s->materialName.c_str()); } Part::TriList::Ref triList = part.newTriList(material); triList->twoSided = false; triList->indexArray = s->cpuIndex; } groupTable.deleteValues(); groupTable.clear(); debugPrintf("Done loading. %d vertices, %d faces, %d frames\n\n", cookVertex.size(), numTris, N); loadTimer.after("Loading"); }