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