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/ply/ply_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 00024 namespace { 00025 00026 enum class VertexAttributeType { 00027 Pos, 00028 Normal, 00029 Color, 00030 Unknown 00031 }; 00032 enum class VertexAttributeDataType { 00033 v_char,// character 1 00034 v_uchar,// unsigned character 1 00035 v_short,// short integer 2 00036 v_ushort,// unsigned short integer 2 00037 v_int,// integer 4 00038 v_uint,// unsigned integer 4 00039 v_float,// single-precision float 4 00040 v_double,// double-precision float 8 00041 v_unknown 00042 }; 00043 00044 VertexAttributeDataType toType(string s){ 00045 if (s=="char"){ 00046 return VertexAttributeDataType::v_char; 00047 } 00048 if (s=="uchar"){ 00049 return VertexAttributeDataType::v_uchar; 00050 } 00051 if (s=="short"){ 00052 return VertexAttributeDataType::v_short; 00053 } 00054 if (s=="ushort"){ 00055 return VertexAttributeDataType::v_ushort; 00056 } 00057 if (s=="int"){ 00058 return VertexAttributeDataType::v_int; 00059 } 00060 if (s=="uint"){ 00061 return VertexAttributeDataType::v_uint; 00062 } 00063 if (s=="float"){ 00064 return VertexAttributeDataType::v_float; 00065 } 00066 if (s=="double"){ 00067 return VertexAttributeDataType::v_double; 00068 } 00069 logWarning("Unknown type "+s); 00070 return VertexAttributeDataType::v_unknown; 00071 } 00072 00073 struct VertexMapping{ 00074 VertexAttributeType type; 00075 VertexAttributeDataType dataType; 00076 }; 00077 00078 // from http://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring 00079 /*string getFileContents(string filename) 00080 { 00081 ifstream in{filename, ios::in | ios::binary}; 00082 if (in) 00083 { 00084 std::string contents; 00085 in.seekg(0, std::ios::end); 00086 contents.resize(in.tellg()); 00087 in.seekg(0, std::ios::beg); 00088 in.read(&contents[0], contents.size()); 00089 in.close(); 00090 return contents; 00091 } 00092 logError(string{"Error loading file "}+filename+" error "+std::to_string(errno)); 00093 return ""; 00094 } */ 00095 00096 std::string fixPathEnd(std::string &path){ 00097 if (path.length() == 0){ 00098 return path; 00099 } 00100 char lastChar = path[path.length()-1]; 00101 if (lastChar != '/'){ 00102 return path + "/"; 00103 } 00104 return path; 00105 } 00106 00107 vec3 toVec3(vector<string> &tokens, int offset, float div=1){ 00108 vec3 res{0,0,0}; 00109 for (int i=0;i<3;i++){ 00110 if (i+offset < tokens.size()){ 00111 res[i] = atof(tokens[i+offset].c_str())/div; 00112 } 00113 } 00114 return res; 00115 } 00116 00117 // ObjFace toObjFace(vector<string> &tokens){ 00118 // ObjFace res; 00119 // for (int i=1; i<tokens.size(); i++) { 00120 // string & p = tokens[i]; 00121 // replace(p, "//","/0/"); 00122 // 00123 // if (p.length()==0){ 00124 // continue; 00125 // } 00126 // 00127 // ObjVertex o{0,0,0}; 00128 // 00129 // stringstream ss{p}; 00130 // char buffer[50]; 00131 // ss.getline(buffer,50, '/'); 00132 // o.vertexPositionIdx = atoi(buffer); 00133 // if (ss.good()){ 00134 // ss.getline(buffer,50, '/'); 00135 // o.textureIdx = atoi(buffer); 00136 // } 00137 // if (ss.good()){ 00138 // ss.getline(buffer,50, '/'); 00139 // o.normalIdx = atoi(buffer); 00140 // } 00141 // res.push_back(o); 00142 // } 00143 // return res; 00144 // } 00145 00146 00147 } 00148 00149 std::shared_ptr<MeshData> loadPlyData(std::string objSource){ 00150 auto res = make_shared<MeshData>(); 00151 stringstream ss{objSource}; 00152 const int bufferSize = 256; 00153 char buffer[bufferSize]; 00154 char buffer2[bufferSize]; 00155 bool headerEnded = false; 00156 int vertices = -1; 00157 int faces = -1; 00158 int count = 0; 00159 00160 vector<vec3> vertexPos; 00161 vector<vec3> normals; 00162 vector<vec4> colors; 00163 vector<unsigned short> indices; 00164 00165 vector<VertexMapping> mapping; 00166 00167 while (ss.good()){ 00168 ss.getline(buffer, bufferSize); 00169 stringstream likeTokensizer{buffer}; 00170 vector<string> tokens; 00171 while (likeTokensizer.good()) { 00172 likeTokensizer.getline(buffer2, bufferSize, ' '); 00173 tokens.push_back(buffer2); 00174 } 00175 if (tokens.size()==0){ 00176 continue; 00177 } 00178 if (tokens[0] == "ply"){ 00179 00180 } else if (tokens[0] == "format"){ 00181 if (tokens[1] != "ascii"){ 00182 logWarning("Only PLY ascii is supported"); 00183 } 00184 } else if (tokens[0] == "element"){ 00185 if (tokens[1] == "vertex"){ 00186 vertices = atoi(tokens[2].c_str()); 00187 } else if (tokens[1] == "face"){ 00188 faces = atoi(tokens[2].c_str()); 00189 } 00190 } else if (tokens[0] == "property"){ 00191 if (tokens[2]=="x"){ 00192 mapping.push_back({VertexAttributeType::Pos,toType(tokens[1])}); 00193 } else if (tokens[2]=="y" || tokens[2]=="z"){ 00194 00195 } else if (tokens[2]=="nx"){ 00196 mapping.push_back({VertexAttributeType::Normal,toType(tokens[1])}); 00197 } else if (tokens[2]=="ny" || tokens[2]=="nz"){ 00198 00199 } else if (tokens[2]=="red"){ 00200 mapping.push_back({VertexAttributeType::Color,toType(tokens[1])}); 00201 } else if (tokens[2]=="green" || tokens[2]=="blue"){ 00202 } else if (tokens[1]=="list"){ 00203 00204 } else { 00205 mapping.push_back({VertexAttributeType::Unknown,toType(tokens[1])}); 00206 } 00207 } else if (tokens[0] == "end_header"){ 00208 headerEnded = true; 00209 if (vertices == -1){ 00210 logWarning("Undefined vertex count"); 00211 } 00212 if (faces == -1){ 00213 logWarning("Undefined face count"); 00214 } 00215 } else if (headerEnded){ 00216 count++; 00217 bool isVertex = count <= vertices; 00218 if (isVertex){ 00219 int idx = 0; 00220 for (auto t : mapping){ 00221 if (t.type == VertexAttributeType::Pos){ 00222 vertexPos.push_back(toVec3(tokens, idx)); 00223 } 00224 else if (t.type == VertexAttributeType::Normal){ 00225 normals.push_back(toVec3(tokens, idx)); 00226 } else if (t.type == VertexAttributeType::Color) { 00227 colors.push_back(vec4(toVec3(tokens, idx, 255),1)); 00228 } 00229 idx += (t.type == VertexAttributeType::Unknown) ? 1 : 3; 00230 } 00231 } else { 00232 int count = atoi(tokens[0].c_str()); 00233 for (int i=0;i<count;i++){ 00234 if (i>2){ 00235 // add first and last node to do simple triangulation 00236 indices.push_back(atoi(tokens[1].c_str())); 00237 indices.push_back(atoi(tokens[i].c_str())); 00238 } 00239 indices.push_back(atoi(tokens[i+1].c_str())); 00240 } 00241 00242 } 00243 } 00244 } 00245 res->setPosition(vertexPos); 00246 if (normals.size()>0){ 00247 res->setNormal(normals); 00248 } 00249 if (colors.size()>0){ 00250 res->setColor(colors); 00251 } 00252 res->setSubmesh(0, indices, MeshType::Triangles); 00253 return res; 00254 } 00255 00256 00257 std::shared_ptr<MeshData> loadPlyData(std::string path, std::string filename){ 00258 path = fixPathEnd(path); 00259 00260 string fileSrc;// = getFileContents(path+filename); 00261 Project::loadTextResource(path+filename,fileSrc); 00262 return loadPlyData(fileSrc); 00263 } 00264 }