kick
/Users/morten/Programmering/cpp/kick/src/kick/obj/obj_load.cpp
00001 //
00002 //  ObjLoader.cpp
00003 //  KickObjLoader
00004 //
00005 //  Created by morten on 8/31/13.
00006 //  Copyright (c) 2013 morten. All rights reserved.
00007 //
00008 
00009 #include "kick/obj/obj_load.h"
00010 #include "kick/core/project.h"
00011 #include <fstream>
00012 #include <string>
00013 #include <cstring>
00014 #include <sstream>
00015 #include <cerrno>
00016 #include "glm/ext.hpp"
00017 #include "kick/core/debug.h"
00018 
00019 using namespace std;
00020 using namespace glm;
00021 
00022 namespace kick {
00023     // from http://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring
00024     /*string getFileContents(string filename)
00025     {
00026         ifstream in{filename, ios::in | ios::binary};
00027         if (in)
00028         {
00029             std::string contents;
00030             in.seekg(0, std::ios::end);
00031             contents.resize(in.tellg());
00032             in.seekg(0, std::ios::beg);
00033             in.read(&contents[0], contents.size());
00034             in.close();
00035             return contents;
00036         }
00037         logError(string{"Error loading file "}+filename+" error "+std::to_string(errno));
00038         return "";
00039     } */
00040     
00041     vec4 toVec4(vector<string> &tokens){
00042         vec4 res{0,0,0,1};
00043         for (int i=0;i<4;i++){
00044             if (i+1 < tokens.size()){
00045                 res[i] = atof(tokens[i+1].c_str());
00046             }
00047         }
00048         return res;
00049     }
00050     
00051     vec3 toVec3(vector<string> &tokens){
00052         vec3 res{0,0,0};
00053         for (int i=0;i<3;i++){
00054             if (i+1 < tokens.size()){
00055                 res[i] = atof(tokens[i+1].c_str());
00056             }
00057         }
00058         return res;
00059     }
00060     
00061     bool replace(std::string& str, const std::string& from, const std::string& to) {
00062         size_t start_pos = str.find(from);
00063         if(start_pos == std::string::npos)
00064             return false;
00065         str = str.replace(start_pos, from.length(), to);
00066         return true;
00067     }
00068     
00069     ObjFace toObjFace(vector<string> &tokens){
00070         ObjFace res;
00071         for (int i=1; i<tokens.size(); i++) {
00072             string & p = tokens[i];
00073             replace(p, "//","/0/");
00074 
00075             if (p.length()==0){
00076                 continue;
00077             }
00078 
00079             ObjVertex o{0,0,0};
00080             
00081             stringstream ss{p};
00082             char buffer[50];
00083             ss.getline(buffer,50, '/');
00084             o.vertexPositionIdx = atoi(buffer);
00085             if (ss.good()){
00086                 ss.getline(buffer,50, '/');
00087                 o.textureIdx = atoi(buffer);
00088             }
00089             if (ss.good()){
00090                 ss.getline(buffer,50, '/');
00091                 o.normalIdx = atoi(buffer);
00092             }
00093             res.push_back(o);
00094         }
00095         return res;
00096     }
00097     
00098     void parseMaterialLib(std::string & materialLib, ObjData & dest){
00099         const int bufferSize = 256;
00100         char buffer[bufferSize];
00101         char buffer2[bufferSize];
00102         stringstream ss{materialLib};
00103         
00104         while (ss.good()){
00105             ss.getline(buffer, bufferSize);
00106             stringstream likeTokensizer{buffer};
00107             vector<string> tokens;
00108             while (likeTokensizer.good()) {
00109                 likeTokensizer.getline(buffer2, bufferSize, ' ');
00110                 tokens.push_back(buffer2);
00111             }
00112             if (tokens.size()==0){
00113                 continue;
00114             }
00115             if (tokens[0] == "newmtl"){
00116                 vec3 zero{0,0,0};
00117                 ObjMaterial material{tokens[1],zero,zero,zero,50,1};
00118                 dest.materials.push_back(material);
00119             } else {
00120                 if (dest.materials.size()==0){
00121                     continue;
00122                 }
00123                 ObjMaterial & currentMat = dest.materials.back();
00124                 if (tokens[0] == "Ka"){
00125                     currentMat.ambientColor = toVec3(tokens);
00126                 } else if (tokens[0] == "Kd"){
00127                     currentMat.diffuseColor = toVec3(tokens);
00128                 } else if (tokens[0] == "Ks"){
00129                     currentMat.specularColor = toVec3(tokens);
00130                 } else if (tokens[0] == "d"){
00131                     currentMat.transparent = atoi(tokens[1].c_str());
00132                 } else if (tokens[0] == "illum"){
00133                     int illumMode = atoi(tokens[1].c_str());
00134                     currentMat.illuminationModes.push_back(static_cast<ObjIlluminationMode>(illumMode));
00135                 } else if (tokens[0] == "map_Ka"){
00136                     
00137                 } else if (tokens[0] == "map_Kd"){
00138                 } else if (tokens[0] == "map_Ks"){
00139                 } else if (tokens[0] == "map_Ns"){
00140                 } else if (tokens[0] == "map_d"){
00141                 } else if (tokens[0] == "map_bump" || tokens[0] == "bump" ){
00142                 } else if (tokens[0] == "map_disp" || tokens[0] == "disp" ){
00143                 } else if (tokens[0] == "map_decal" || tokens[0] == "decal" ){
00144                 }
00145             }
00146         }
00147     }
00148     
00149     ObjData loadObjData(std::string objSource, std::function<std::string (std::string)> materialMap){
00150         ObjData res;
00151         stringstream ss{objSource};
00152         const int bufferSize = 256;
00153         char buffer[bufferSize];
00154         char buffer2[bufferSize];
00155         bool initialComment = true;
00156         while (ss.good()){
00157             ss.getline(buffer, bufferSize);
00158             stringstream likeTokensizer{buffer};
00159             vector<string> tokens;
00160             while (likeTokensizer.good()) {
00161                 likeTokensizer.getline(buffer2, bufferSize, ' ');
00162                 tokens.push_back(buffer2);
00163             }
00164             if (tokens.size()==0){
00165                 continue;
00166             }
00167             initialComment = initialComment && (tokens[0] == "#");
00168             int currentIndex = static_cast<int>(res.faces.size()) + 1;
00169             if (tokens[0] == "#"){ // comment
00170                 if (initialComment){
00171                     res.initialComment += string(buffer + 2) + "\n";
00172                 }
00173             } else if (tokens[0] == "v"){ // vertex position
00174                 vec4 vertexPosition = toVec4(tokens);
00175                 res.vertexPositions.push_back(vertexPosition);
00176             } else if (tokens[0] == "vt"){ // vertex texture coordinates
00177                 vec3 textureCoord = toVec3(tokens);
00178                 res.textureCoords.push_back(textureCoord);
00179             } else if (tokens[0] == "vn"){ // vertex normal
00180                 vec3 normal = toVec3(tokens);
00181                 res.normals.push_back(normal);
00182             } else if (tokens[0] == "f"){ // face
00183                 res.faces.push_back(toObjFace(tokens));
00184             } else if (tokens[0] == "mtllib"){ // material library
00185                 string materialLib = materialMap(tokens[1]);
00186                 parseMaterialLib(materialLib, res);
00187             } else if (tokens[0] == "usemtl"){ // use material
00188                 res.materialChanges.push_back({currentIndex, tokens[1]});
00189             } else if (tokens[0] == "o"){ // named object
00190                 res.namedObjects.push_back({currentIndex, tokens[1]});
00191             } else if (tokens[0] == "g"){ // polygon group
00192                 res.polygonGroups.push_back({currentIndex, tokens[1]});
00193             } else if (tokens[0] == "s"){ // smoothing groups
00194                 int smoothingGroup = 0; // 0 = no smoothing
00195                 if (tokens[1] != "off"){
00196                     smoothingGroup = atoi(tokens[1].c_str());
00197                 }
00198                 res.smoothGroups.push_back({currentIndex, smoothingGroup});
00199             }
00200         }
00201 
00202         return res;
00203     }
00204     
00205     std::string fixPathEnd(std::string &path){
00206         if (path.length() == 0){
00207             return path;
00208         }
00209         char lastChar = path[path.length()-1];
00210         if (lastChar != '/'){
00211             return path + "/";
00212         }
00213         return path;
00214     }
00215     
00216     ObjData loadObjData(std::string path, std::string filename){
00217         path = fixPathEnd(path);
00218         string file;
00219         Project::loadTextResource(path+filename,file);
00220         std::function<std::string (std::string)>  materialLoader = [&](string filename){
00221             string mat;
00222             Project::loadTextResource(path+filename,file);
00223             return mat;
00224         };
00225         return loadObjData(file, materialLoader);
00226     }
00227 }
 All Classes Functions Variables