kick
/Users/morten/Programmering/cpp/kick/src/kick/mesh/mesh_data.cpp
00001 //
00002 //  MeshData.cpp
00003 //  KickCPP
00004 //
00005 //  Created by Morten Nobel-Jørgensen on 10/20/13.
00006 //  Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved.
00007 //
00008 
00009 #include "kick/mesh/mesh_data.h"
00010 #include <algorithm>
00011 #include <iostream>
00012 #include <locale> 
00013 #include "kick/core/debug.h"
00014 #include <glm/gtc/constants.hpp>
00015 
00016 using namespace std;
00017 using namespace glm;
00018 
00019 
00020 namespace kick {
00021 
00022     namespace { // helper functions
00023         // helper function that returns lowercase of string
00024         string to_lower(string s){
00025             std::locale loc;
00026             for (int i=0;i<s.size();i++){
00027                 s[i] = std::tolower(s[i],loc);
00028             }
00029             return s;
00030         }
00031 
00035         template<typename T>
00036         size_t add_interleaved_record(const std::vector<T>& data, vector<InterleavedRecord>& interleaved, size_t offset, VertexAttributeSemantic semantic){
00037             if (data.size() == 0){
00038                 return offset;
00039             }
00040             int vectorLength = (int)data[0].length();
00041 
00042             InterleavedRecord record{
00043                     semantic,
00044                     BUFFER_OFFSET(offset),
00045                     vectorLength,
00046                     false,
00047                     GL_FLOAT};
00048             interleaved.push_back(record);
00049             return offset + sizeof(T);
00050         }
00051     }
00052 
00053     MeshData::MeshData()
00054     {
00055         setSubmesh(0, {}, MeshType::Triangles);
00056     }
00057     
00058     void MeshData::setPosition(const std::vector<glm::vec3> &p) {
00059         mPosition = p;
00060     }
00061     
00062     const std::vector<glm::vec3>& MeshData::position() {
00063         return mPosition;
00064     }
00065     
00066     void MeshData::setNormal(const std::vector<glm::vec3> &n) {
00067         mNormal = n;
00068     }
00069     
00070     const std::vector<glm::vec3>& MeshData::normal() {
00071         return mNormal;
00072     }
00073     
00074     void MeshData::setTexCoord0(const std::vector<glm::vec2> &u1) {
00075         mTexCoord0 = u1;
00076     }
00077     
00078     const std::vector<glm::vec2>& MeshData::texCoord0() {
00079         return mTexCoord0;
00080     }
00081     
00082     void MeshData::setTexCoord1(const std::vector<glm::vec2> &u2) {
00083         mTexCoord1 = u2;
00084     }
00085     
00086     const std::vector<glm::vec2>& MeshData::texCoord1() {
00087         return mTexCoord1;
00088     }
00089     
00090     void MeshData::setTangent(const std::vector<glm::vec3> &t) {
00091         mTangent = t;
00092     }
00093     
00094     const std::vector<glm::vec3>& MeshData::tangent() {
00095         return mTangent;
00096     }
00097     
00098     void MeshData::setColor(const std::vector<glm::vec4> &c) {
00099         mColor = c;
00100     }
00101     
00102     const std::vector<glm::vec4>& MeshData::color(){
00103         return mColor;
00104     }
00105     
00106     GLsizei MeshData::submeshSize(unsigned int index){
00107         return static_cast<GLsizei>(subMeshes[index].indices.size());
00108     }
00109     
00110     unsigned int MeshData::submeshesCount(){
00111         return static_cast<unsigned int>(subMeshes.size());
00112     }
00113 
00114     size_t MeshData::computeInterleavedDataSize(){
00115         size_t numberOfElements = static_cast<int>(mPosition.size());
00116         size_t vertexSize = 3;
00117         if (mNormal.size() > 0) {
00118             vertexSize += 3;
00119         }
00120         if (mTexCoord0.size() > 0) {
00121             vertexSize += 2;
00122         }
00123         if (mTexCoord1.size() > 0) {
00124             vertexSize += 2;
00125         }
00126         if (mTangent.size() > 0) {
00127             vertexSize += 4;
00128         }
00129         if (mColor.size() > 0) {
00130             vertexSize += 4;
00131         }
00132         return vertexSize * numberOfElements;
00133     }
00134     
00138     template<typename T>
00139     size_t add_data(const std::vector<T>& data, vector<float>& interleaved, size_t offset, int stride, int elements){
00140         if (data.size() == 0){
00141             return offset;
00142         }
00143         size_t vectorLength = data[0].length();
00144         size_t index = offset;
00145         for (int i=0;i<elements;i++){
00146             for (int j=0;j<vectorLength;j++){
00147                 if (i < data.size()){
00148                     interleaved[index+j] = data[i][j];
00149                 } else {
00150                     interleaved[index+j] = 0;
00151                 }
00152             }
00153             index += stride;
00154         }
00155         return offset + vectorLength;
00156     }
00157     
00158     vector<float> MeshData::interleavedData(){
00159         const size_t floatElements = computeInterleavedDataSize();
00160         vector<float> res(floatElements);
00161         if (floatElements == 0){
00162             return res;
00163         }
00164         int elements = mPosition.size();
00165         const int stride = floatElements / elements;
00166         size_t offset = add_data(mPosition, res, 0, stride, elements);
00167         offset = add_data(mNormal, res, offset, stride, elements);
00168         offset = add_data(mTexCoord0, res, offset, stride, elements);
00169         offset = add_data(mTexCoord1, res, offset, stride, elements);
00170         offset = add_data(mTangent, res, offset, stride, elements);
00171         offset = add_data(mColor, res, offset, stride, elements);
00172         return res;
00173     }
00174 
00175     vector<InterleavedRecord> MeshData::interleavedFormat() {
00176         vector<InterleavedRecord> res;
00177         size_t offset = add_interleaved_record(mPosition, res, 0, VertexAttributeSemantic::Position);
00178         offset = add_interleaved_record(mNormal, res, offset, VertexAttributeSemantic::Normal);
00179         offset = add_interleaved_record(mTexCoord0, res, offset, VertexAttributeSemantic::Uv1);
00180         offset = add_interleaved_record(mTexCoord1, res, offset, VertexAttributeSemantic::Uv2);
00181         offset = add_interleaved_record(mTangent, res, offset, VertexAttributeSemantic::Tangent);
00182         offset = add_interleaved_record(mColor, res, offset, VertexAttributeSemantic::Color);
00183         
00184         for (auto & record : res){
00185             record.stride = static_cast<GLsizei>(offset);
00186         }
00187         
00188         return res;
00189     }
00190     
00191     vector<GLushort> MeshData::indicesConcat(){
00192         vector<GLushort> res;
00193         for (auto & v : subMeshes){
00194             res.insert(res.end(), v.indices.begin(), v.indices.end());
00195         }
00196         return res;
00197     }
00198     
00199     vector<SubMeshData> MeshData::indicesFormat(){
00200         vector<SubMeshData> res;
00201         size_t offset = 0;
00202         for (auto & v : subMeshes){
00203             int indexCount =v.indices.size();
00204             if (indexCount == 0){
00205                 indexCount = -mPosition.size();
00206             }
00207             SubMeshData record{
00208                 static_cast<GLsizei>(indexCount),
00209                 BUFFER_OFFSET(offset),
00210                 static_cast<GLenum>(v.meshType),
00211                 GL_UNSIGNED_SHORT
00212             };
00213             
00214             res.push_back(record);
00215             offset += sizeof(GLushort) * v.indices.size();
00216         }
00217         return res;
00218     }
00219     
00220     void MeshData::setSubmesh(unsigned int index, const std::vector<GLushort> &indices, MeshType meshType){
00221         while (subMeshes.size() <= index){
00222             subMeshes.push_back({{}, MeshType::Triangles});
00223         }
00224         subMeshes[index].indices = indices;
00225         subMeshes[index].meshType = meshType;
00226     }
00227     
00228     const vector<GLushort>& MeshData::submeshIndices(unsigned int index) const {
00229         return subMeshes.at(index).indices;
00230     }
00231     
00232     const MeshType MeshData::submeshType(unsigned int index) const{
00233         return subMeshes.at(index).meshType;
00234     }
00235     
00236     void MeshData::recomputeNormals(){
00237         // empty
00238         mNormal.resize(mPosition.size());
00239         for (int i=0;i< mNormal.size();i++){
00240             mNormal[i] = vec3{0};
00241         }
00242         
00243         for (auto & v : subMeshes){
00244             auto & submesh = v.indices;
00245             if (v.meshType != MeshType::Triangles){
00246 //                throw std::invalid_argument();
00247                 logError("Recalcualte normals only valid for triangles");
00248                 return;
00249             }
00250             size_t triangleCount = submesh.size()/3;
00251             for (int a = 0; a < triangleCount; a++) {
00252                 GLuint i1 = submesh[a * 3];
00253                 GLuint i2 = submesh[a * 3 + 1];
00254                 GLuint i3 = submesh[a * 3 + 2];
00255                 
00256                 vec3 v1 = mPosition[i1];
00257                 vec3 v2 = mPosition[i2];
00258                 vec3 v3 = mPosition[i3];
00259                 
00260                 vec3 v1v2 = normalize(v2 - v1);
00261                 vec3 v1v3 = normalize(v3 - v1);
00262                 
00263                 vec3 faceNormal = normalize(cross(v1v2, v1v3));
00264                 float weight1 = acos(std::max(-1.0f, std::min(1.0f, dot(v1v2, v1v3))));
00265                 
00266                 vec3 v2v3 = normalize(v3 - v2);
00267                                 float weight2 = (float)(pi<float>() - acos(std::max(-1.0f, std::min(1.0f, dot(v1v2, v2v3)))));
00268                                 float weight3 = (float)(pi<float>() - weight1 - weight2);
00269                 mNormal[i1] += weight1 * faceNormal;
00270                 mNormal[i2] += weight2 * faceNormal;
00271                 mNormal[i3] += weight3 * faceNormal;
00272             }
00273         }
00274         for (int i=0;i< mNormal.size();i++){
00275             if (mNormal[i] != vec3{0}){
00276                 mNormal[i] = normalize(mNormal[i]);
00277             }
00278         }
00279     }
00280 
00281     GLenum MeshData::meshUsageVal() { return static_cast<GLenum>(mMeshUsage); }
00282 
00283 
00284 #define RETURN_IF_EQUAL(X) if (to_lower(name) == to_lower(#X)) return VertexAttributeSemantic::X;
00285     VertexAttributeSemantic to_semantic(std::string name){
00286         RETURN_IF_EQUAL(Position);
00287         RETURN_IF_EQUAL(Normal);
00288         RETURN_IF_EQUAL(Uv1);
00289         RETURN_IF_EQUAL(Uv2);
00290         RETURN_IF_EQUAL(Tangent);
00291         RETURN_IF_EQUAL(Color);
00292         return VertexAttributeSemantic::Unknown;
00293     }
00294 
00295     std::string to_string(VertexAttributeSemantic semantic){
00296         switch (semantic) {
00297             case VertexAttributeSemantic::Position:
00298                 return "Position";
00299             case VertexAttributeSemantic::Normal:
00300                 return "Normal";
00301             case VertexAttributeSemantic::Uv1:
00302                 return "Uv1";
00303             case VertexAttributeSemantic::Uv2:
00304                 return "Uv2";
00305             case VertexAttributeSemantic::Tangent:
00306                 return "Tangent";
00307             case VertexAttributeSemantic::Color:
00308                 return "Color";
00309             case VertexAttributeSemantic::Unknown:
00310                 return "Unknown";
00311             default:
00312                 //throw invalid_argument("Unknown semantic");
00313                 logWarning("Unknown semantic");
00314                 return "Unknown";
00315         }
00316     }
00317 
00318     MeshUsage MeshData::meshUsage() const {
00319         return mMeshUsage;
00320     }
00321 
00322     void MeshData::setMeshUsage(MeshUsage meshUsage) {
00323         MeshData::mMeshUsage = meshUsage;
00324     }
00325 
00326     void MeshData::recomputeBounds() {
00327         mBounds.reset();
00328         for (auto p:mPosition){
00329             mBounds.expand(p);
00330         }
00331     }
00332 
00333     void MeshData::setBounds(const Bounds3 &bounds) {
00334         mBounds = bounds;
00335     }
00336 
00337     const Bounds3 &MeshData::bounds() {
00338         return mBounds;
00339     }
00340 }
00341 
 All Classes Functions Variables