kick
/Users/morten/Programmering/cpp/kick/src/kick/obj/obj_interleaved_data.cpp
00001 //
00002 //  ObjInterleavedData.cpp
00003 //  KickObjLoader
00004 //
00005 //  Created by morten on 9/2/13.
00006 //  Copyright (c) 2013 morten. All rights reserved.
00007 //
00008 
00009 #include "obj_interleaved_data.h"
00010 #include <unordered_map>
00011 #include <glm/glm.hpp>
00012 #include <cassert>
00013 #include <algorithm>
00014 
00015 using namespace std;
00016 using namespace glm;
00017 
00018 namespace kick {
00019     
00020     struct ObjVertexHash {
00021         std::size_t operator()(const ObjVertex& k) const {
00022             return (( k.vertexPositionIdx << 16 ) ^ ( k.textureIdx << 8 )) ^ k.normalIdx;
00023         }
00024     };
00025     
00026     struct ObjVertexEqual {
00027         bool operator()(const ObjVertex& lhs, const ObjVertex& rhs) const {
00028             return lhs.vertexPositionIdx == rhs.vertexPositionIdx &&
00029             lhs.textureIdx == rhs.textureIdx &&
00030             lhs.normalIdx == rhs.normalIdx;
00031         }
00032     };
00033     
00034     using ObjVertexHashTable = unordered_map<ObjVertex,int,ObjVertexHash, ObjVertexEqual>;
00035     
00036     int getCreateIndex(ObjVertex &vertexIndex, int nextIndex, ObjVertexHashTable& usedVertices){
00037         auto pos = usedVertices.find(vertexIndex);
00038         if (pos != usedVertices.end()){
00039             return pos->second;
00040         }
00041         usedVertices.emplace(vertexIndex, nextIndex);
00042         return nextIndex;
00043     }
00044     
00045     ObjInterleavedData::ObjInterleavedData(ObjData & objData, bool includeTextureCoordinates, bool includeNormals, int vertexPositionSize, int texCoordinateSize)
00046     :includeTextureCoordinates(includeTextureCoordinates), includeNormals(includeNormals), vertexPositionSize(vertexPositionSize), texCoordinateSize(texCoordinateSize) {
00047         
00048         vertexLength = vertexPositionSize;
00049         if (includeTextureCoordinates){
00050             textureOffset = vertexLength;
00051             vertexLength += texCoordinateSize;
00052         }
00053         if (includeNormals){
00054             normalsOffset = vertexLength;
00055             vertexLength += 3;
00056         }
00057         
00058         indices.push_back({"___Default material___", {}});
00059         
00060         ObjInterleavedIndex * currentIndex = &indices.back();
00061         ObjVertexHashTable usedVertices{42,ObjVertexHash{}, ObjVertexEqual{}};
00062         
00063         int vertexCount = 0;
00064         int faceCount = 0;
00065         auto materialChanges = objData.materialChanges.begin();
00066         for (auto & face : objData.faces){
00067             faceCount++;
00068             if (materialChanges != objData.materialChanges.end()){
00069                 if (materialChanges->faceIndex == faceCount){
00070                     bool foundMaterial = false;
00071                     for (auto & idx : indices) {
00072                         if (idx.materialName == materialChanges->name){
00073                             foundMaterial = true;
00074                             currentIndex = &idx;
00075                             break;
00076                         }
00077                     }
00078                     if (!foundMaterial){
00079                         indices.push_back({materialChanges->name, {}});
00080                         currentIndex = &indices.back();
00081                     }
00082                     materialChanges++;
00083                 }
00084             }
00085             for (int i=2;i < face.size();i++){
00086                 int triangle[] = {0, i-1, i};
00087                 for (int triangleIndex : triangle){
00088                     auto & vertexIndexObject = face[triangleIndex];
00089                     int vertexIndex = getCreateIndex(vertexIndexObject, vertexCount, usedVertices);
00090                     bool existInInterleavedData = vertexIndex != vertexCount;
00091                     if (!existInInterleavedData){
00092                         // read data
00093                         vec4 vertexPosition = objData.vertexPositions[vertexIndexObject.vertexPositionIdx - 1];
00094                         vec3 textureCoord{0,0,0};
00095                         if (vertexIndexObject.textureIdx > 0 && includeTextureCoordinates){
00096                             textureCoord = objData.textureCoords[vertexIndexObject.textureIdx - 1];
00097                         }
00098                         vec3 normal;
00099                         if (vertexIndexObject.normalIdx > 0 && includeNormals){
00100                             normal = objData.normals[vertexIndexObject.normalIdx-1];
00101                         }
00102                         // write interleaved data
00103                         for (int j=0;j<vertexPositionSize;j++){
00104                             interleavedData.push_back(vertexPosition[j]);
00105                         }
00106                         if (includeTextureCoordinates){
00107                             for (int j=0;j<texCoordinateSize;j++){
00108                                 interleavedData.push_back(textureCoord[j]);
00109                             }
00110                         }
00111                         if (includeNormals){
00112                             for (int j=0;j<3;j++){
00113                                 interleavedData.push_back(normal[j]);
00114                             }
00115                         }
00116                         vertexCount++;
00117                     }
00118                     currentIndex->vertexIndices.push_back(vertexIndex);
00119                 }
00120             }
00121         }
00122         
00123         // remove unused materials
00124         indices.erase(std::remove_if(indices.begin(), indices.end(), [](const ObjInterleavedIndex &a){ return a.vertexIndices.size()==0;}),
00125                    indices.end());
00126     }
00127     
00128     int ObjInterleavedData::vertexCount(){
00129         return (int)(interleavedData.size() / vertexLength);
00130     }
00131     
00132     glm::vec4 ObjInterleavedData::vertex(int index){
00133         int i = vertexLength*index;
00134         return glm::vec4{interleavedData[i], interleavedData[i+1], interleavedData[i+2], vertexPositionSize==4?interleavedData[i+3]:1};
00135     }
00136     
00137     void ObjInterleavedData::setVertex(int index, glm::vec4 value){
00138         int i = vertexLength*index;
00139         for (int j=0;j<vertexPositionSize;j++){
00140             interleavedData[i+j] = value[j];
00141         }
00142     }
00143     glm::vec3 ObjInterleavedData::textureCoordinate(int index){
00144         int i = vertexLength*index + textureOffset;
00145         return glm::vec3{interleavedData[i], interleavedData[i+1], texCoordinateSize==3?interleavedData[i+2]:0};
00146     }
00147     void ObjInterleavedData::setTextureCoordinate(int index, glm::vec3 value){
00148         int i = vertexLength*index + textureOffset;
00149         for (int j=0;j<texCoordinateSize;j++){
00150             interleavedData[i+j] = value[j];
00151         }
00152     }
00153     glm::vec3 ObjInterleavedData::normal(int index){
00154         int i = vertexLength*index + normalsOffset;
00155         return glm::vec3{interleavedData[i], interleavedData[i+1], interleavedData[i+2]};
00156     }
00157     
00158     void ObjInterleavedData::setNormal(int index, glm::vec3 value){
00159         int i = vertexLength*index + normalsOffset;
00160         for (int j=0;j<3;j++){
00161             interleavedData[i+j] = value[j];
00162         }
00163     }
00164 }
 All Classes Functions Variables