kick
|
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 }