diff options
Diffstat (limited to 'gfx/models/obj_loader.cpp')
-rw-r--r-- | gfx/models/obj_loader.cpp | 429 |
1 files changed, 0 insertions, 429 deletions
diff --git a/gfx/models/obj_loader.cpp b/gfx/models/obj_loader.cpp deleted file mode 100644 index 75ab251..0000000 --- a/gfx/models/obj_loader.cpp +++ /dev/null @@ -1,429 +0,0 @@ -#include "obj_loader.h" -#include <algorithm> -#include <fstream> -#include <map> -#include <memory> -#include <resource.h> -#include <stdexcept> -#include <utility> - -static bool CompareOBJIndexPtr(const OBJIndex * a, const OBJIndex * b); -static inline unsigned int FindNextChar(unsigned int start, const char * str, unsigned int length, char token); -static inline unsigned int ParseOBJIndexValue(const std::string & token, unsigned int start, unsigned int end); -static inline float ParseOBJFloatValue(const std::string & token, unsigned int start, unsigned int end); -static inline std::vector<std::string> SplitString(const std::string & s, char delim); - -OBJModel::OBJModel(const std::filesystem::path & fileName) -{ - hasUVs = false; - hasNormals = false; - std::ifstream file; - file.open(Resource::mapPath(fileName).c_str()); - - std::string line; - if (file.is_open()) { - while (file.good()) { - getline(file, line); - - unsigned int lineLength = line.length(); - - if (lineLength < 2) { - continue; - } - - const char * lineCStr = line.c_str(); - - switch (lineCStr[0]) { - case 'v': - switch (lineCStr[1]) { - case 't': - this->uvs.push_back(ParseOBJVec2(line)); - break; - case 'n': - this->normals.push_back(ParseOBJVec3(line)); - break; - case ' ': - case '\t': - this->vertices.push_back(ParseOBJVec3(line)); - } - break; - case 'f': - CreateOBJFace(line); - break; - default: - break; - }; - } - } - else { - throw std::runtime_error {"Unable to load mesh: " + fileName.string()}; - } -} - -void -IndexedModel::CalcNormals() -{ - for (unsigned int i = 0; i < indices.size(); i += 3) { - int i0 = indices[i]; - int i1 = indices[i + 1]; - int i2 = indices[i + 2]; - - glm::vec3 v1 = positions[i1] - positions[i0]; - glm::vec3 v2 = positions[i2] - positions[i0]; - - glm::vec3 normal = glm::normalize(glm::cross(v1, v2)); - - normals[i0] += normal; - normals[i1] += normal; - normals[i2] += normal; - } - - for (unsigned int i = 0; i < positions.size(); i++) { - normals[i] = glm::normalize(normals[i]); - } -} - -IndexedModel -OBJModel::ToIndexedModel() -{ - IndexedModel result; - IndexedModel normalModel; - - unsigned int numIndices = OBJIndices.size(); - - std::vector<OBJIndex *> indexLookup; - - for (unsigned int i = 0; i < numIndices; i++) { - indexLookup.push_back(&OBJIndices[i]); - } - - std::sort(indexLookup.begin(), indexLookup.end(), CompareOBJIndexPtr); - - std::map<OBJIndex, unsigned int> normalModelIndexMap; - std::map<unsigned int, unsigned int> indexMap; - - for (unsigned int i = 0; i < numIndices; i++) { - OBJIndex * currentIndex = &OBJIndices[i]; - - glm::vec3 currentPosition = vertices[currentIndex->vertexIndex]; - glm::vec2 currentTexCoord; - glm::vec3 currentNormal; - - if (hasUVs) { - currentTexCoord = uvs[currentIndex->uvIndex]; - } - else { - currentTexCoord = glm::vec2(0, 0); - } - - if (hasNormals) { - currentNormal = normals[currentIndex->normalIndex]; - } - else { - currentNormal = glm::vec3(0, 0, 0); - } - - unsigned int normalModelIndex; - unsigned int resultModelIndex; - - // Create model to properly generate normals on - const auto it = normalModelIndexMap.find(*currentIndex); - if (it == normalModelIndexMap.end()) { - normalModelIndex = normalModel.positions.size(); - - normalModelIndexMap.insert(std::pair<OBJIndex, unsigned int>(*currentIndex, normalModelIndex)); - normalModel.positions.push_back(currentPosition); - normalModel.texCoords.push_back(currentTexCoord); - normalModel.normals.push_back(currentNormal); - } - else { - normalModelIndex = it->second; - } - - // Create model which properly separates texture coordinates - unsigned int previousVertexLocation = FindLastVertexIndex(indexLookup, currentIndex, result); - - if (previousVertexLocation == (unsigned int)-1) { - resultModelIndex = result.positions.size(); - - result.positions.push_back(currentPosition); - result.texCoords.push_back(currentTexCoord); - result.normals.push_back(currentNormal); - } - else { - resultModelIndex = previousVertexLocation; - } - - normalModel.indices.push_back(normalModelIndex); - result.indices.push_back(resultModelIndex); - indexMap.insert(std::pair<unsigned int, unsigned int>(resultModelIndex, normalModelIndex)); - } - - if (!hasNormals) { - normalModel.CalcNormals(); - - for (unsigned int i = 0; i < result.positions.size(); i++) { - result.normals[i] = normalModel.normals[indexMap[i]]; - } - } - - return result; -}; - -unsigned int -OBJModel::FindLastVertexIndex( - const std::vector<OBJIndex *> & indexLookup, const OBJIndex * currentIndex, const IndexedModel & result) -{ - unsigned int start = 0; - unsigned int end = indexLookup.size(); - unsigned int current = (end - start) / 2 + start; - unsigned int previous = start; - - while (current != previous) { - OBJIndex * testIndex = indexLookup[current]; - - if (testIndex->vertexIndex == currentIndex->vertexIndex) { - unsigned int countStart = current; - - for (unsigned int i = 0; i < current; i++) { - OBJIndex * possibleIndex = indexLookup[current - i]; - - if (possibleIndex == currentIndex) { - continue; - } - - if (possibleIndex->vertexIndex != currentIndex->vertexIndex) { - break; - } - - countStart--; - } - - for (unsigned int i = countStart; i < indexLookup.size() - countStart; i++) { - OBJIndex * possibleIndex = indexLookup[current + i]; - - if (possibleIndex == currentIndex) { - continue; - } - - if (possibleIndex->vertexIndex != currentIndex->vertexIndex) { - break; - } - else if ((!hasUVs || possibleIndex->uvIndex == currentIndex->uvIndex) - && (!hasNormals || possibleIndex->normalIndex == currentIndex->normalIndex)) { - glm::vec3 currentPosition = vertices[currentIndex->vertexIndex]; - glm::vec2 currentTexCoord; - glm::vec3 currentNormal; - - if (hasUVs) { - currentTexCoord = uvs[currentIndex->uvIndex]; - } - else { - currentTexCoord = glm::vec2(0, 0); - } - - if (hasNormals) { - currentNormal = normals[currentIndex->normalIndex]; - } - else { - currentNormal = glm::vec3(0, 0, 0); - } - - for (unsigned int j = 0; j < result.positions.size(); j++) { - if (currentPosition == result.positions[j] - && ((!hasUVs || currentTexCoord == result.texCoords[j]) - && (!hasNormals || currentNormal == result.normals[j]))) { - return j; - } - } - } - } - - return -1; - } - else { - if (testIndex->vertexIndex < currentIndex->vertexIndex) { - start = current; - } - else { - end = current; - } - } - - previous = current; - current = (end - start) / 2 + start; - } - - return -1; -} - -void -OBJModel::CreateOBJFace(const std::string & line) -{ - std::vector<std::string> tokens = SplitString(line, ' '); - - this->OBJIndices.push_back(ParseOBJIndex(tokens[1], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[2], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[3], &this->hasUVs, &this->hasNormals)); - - if ((int)tokens.size() > 4) { - this->OBJIndices.push_back(ParseOBJIndex(tokens[1], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[3], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[4], &this->hasUVs, &this->hasNormals)); - } -} - -OBJIndex -OBJModel::ParseOBJIndex(const std::string & token, bool * hasUVs, bool * hasNormals) -{ - unsigned int tokenLength = token.length(); - const char * tokenString = token.c_str(); - - unsigned int vertIndexStart = 0; - unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); - - OBJIndex result { - .vertexIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd), - .uvIndex = 0, - .normalIndex = 0, - }; - - if (vertIndexEnd >= tokenLength) { - return result; - } - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); - - result.uvIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd); - *hasUVs = true; - - if (vertIndexEnd >= tokenLength) { - return result; - } - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); - - result.normalIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd); - *hasNormals = true; - - return result; -} - -glm::vec3 -OBJModel::ParseOBJVec3(const std::string & line) -{ - unsigned int tokenLength = line.length(); - const char * tokenString = line.c_str(); - - unsigned int vertIndexStart = 2; - - while (vertIndexStart < tokenLength) { - if (tokenString[vertIndexStart] != ' ') { - break; - } - vertIndexStart++; - } - - unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float x = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float y = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float z = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - return glm::vec3(x, y, z); -} - -glm::vec2 -OBJModel::ParseOBJVec2(const std::string & line) -{ - unsigned int tokenLength = line.length(); - const char * tokenString = line.c_str(); - - unsigned int vertIndexStart = 3; - - while (vertIndexStart < tokenLength) { - if (tokenString[vertIndexStart] != ' ') { - break; - } - vertIndexStart++; - } - - unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float x = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float y = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - return glm::vec2(x, y); -} - -static bool -CompareOBJIndexPtr(const OBJIndex * a, const OBJIndex * b) -{ - return a->vertexIndex < b->vertexIndex; -} - -static inline unsigned int -FindNextChar(unsigned int start, const char * str, unsigned int length, char token) -{ - unsigned int result = start; - while (result < length) { - result++; - if (str[result] == token) { - break; - } - } - - return result; -} - -static inline unsigned int -ParseOBJIndexValue(const std::string & token, unsigned int start, unsigned int end) -{ - return std::stoul(token.substr(start, end - start)) - 1; -} - -static inline float -ParseOBJFloatValue(const std::string & token, unsigned int start, unsigned int end) -{ - return std::stof(token.substr(start, end - start)); -} - -static inline std::vector<std::string> -SplitString(const std::string & s, char delim) -{ - std::vector<std::string> elems; - - const char * cstr = s.c_str(); - unsigned int strLength = s.length(); - unsigned int start = 0; - unsigned int end = 0; - - while (end <= strLength) { - while (end <= strLength) { - if (cstr[end] == delim) { - break; - } - end++; - } - - elems.push_back(s.substr(start, end - start)); - start = end + 1; - end = start; - } - - return elems; -} |