/*! \brief load a OBJ material file * \param mtlFilename is the full path to the material file */ void ObjReader::loadMTL(const std::string &mtlFilename) { std::ifstream ifs; ifs.open(mtlFilename.c_str()); if (!ifs.is_open()) { std::cerr << "can't open " << mtlFilename << std::endl; return; } std::shared_ptr<Material> mat; while (ifs.peek() != EOF) { char line[MAX_LINE_LENGTH]; ifs.getline(line, sizeof(line), '\n'); const char* token = line + strspn(line, " \t"); // ignore spaces and tabs if (token[0] == 0) continue; // ignore empty lines if (token[0] == '#') continue; // ignore comments if (!strncmp(token, "newmtl", 6)) { parseSep(token += 6); std::string name(token); printf("Name of the material %s\n", name.c_str()); materials[name] = mat = std::shared_ptr<Material>(new Material (name)); continue; } if (!mat) throw std::runtime_error("invalid material file: newmtl expected first"); if (!strncmp(token, "d", 1)) { parseSep(token += 1); mat->d = getFloat(token); continue; } if (!strncmp(token, "Ns", 1)) { parseSep(token += 2); mat->Ns = getFloat(token); continue; } if (!strncmp(token, "Ns", 1)) { parseSep(token += 2); mat->Ni = getFloat(token); continue; } if (!strncmp(token, "Ka", 2)) { parseSep(token += 2); mat->Ka = getVec3f(token); continue; } if (!strncmp(token, "Kd", 2)) { parseSep(token += 2); mat->Kd = getVec3f(token); continue; } if (!strncmp(token, "Ks", 2)) { parseSep(token += 2); mat->Ks = getVec3f(token); continue; } } ifs.close(); }
/*! \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(); }
/* load material file */ void OBJLoader::loadMTL(const FileName &fileName) { std::ifstream cin; cin.open(fileName.c_str()); if (!cin.is_open()) { std::cerr << "cannot open " << fileName.str() << std::endl; return; } char line[10000]; memset(line, 0, sizeof(line)); OBJMaterial* cur = nullptr; 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; // ignore empty lines if (token[0] == '#') continue; // ignore comments if (!strncmp(token, "newmtl", 6)) { parseSep(token+=6); std::string name(token); Material objmtl; new (&objmtl) OBJMaterial; Ref<SceneGraph::MaterialNode> mtl = new SceneGraph::MaterialNode(objmtl); material[name] = mtl; cur = (OBJMaterial*) &mtl->material; continue; } if (!cur) THROW_RUNTIME_ERROR("invalid material file: newmtl expected first"); if (!strncmp(token, "illum", 5)) { parseSep(token += 5); continue; } if (!strncmp(token, "d", 1)) { parseSep(token += 1); cur->d = getFloat(token); continue; } if (!strncmp(token, "Ns", 2)) { parseSep(token += 2); cur->Ns = getFloat(token); continue; } if (!strncmp(token, "Ni", 2)) { parseSep(token += 2); cur->Ni = getFloat(token); continue; } if (!strncmp(token, "Ka_map", 6)) { continue; } if (!strncmp(token, "Kd_map", 6) || !strncmp(token, "map_Kd", 6)) { parseSep(token += 6); cur->map_Kd = loadTexture(path + FileName(token)); continue; } if (!strncmp(token, "Ks_map", 6)) { continue; } if (!strncmp(token, "Tf_map", 6)) { continue; } if (!strncmp(token, "Displ_map", 9) || !strncmp(token, "map_Displ", 9)) { parseSep(token += 9); cur->map_Displ = loadTexture(path + FileName(token)); continue; } if (!strncmp(token, "Ka", 2)) { parseSep(token += 2); cur->Ka = getVec3f(token); continue; } if (!strncmp(token, "Kd", 2)) { parseSep(token += 2); cur->Kd = getVec3f(token); continue; } if (!strncmp(token, "Ks", 2)) { parseSep(token += 2); cur->Ks = getVec3f(token); continue; } if (!strncmp(token, "Tf", 2)) { parseSep(token += 2); cur->Kt = getVec3f(token); continue; } } cin.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(); }