diff --git a/include/Nazara/Utility/Algorithm.hpp b/include/Nazara/Utility/Algorithm.hpp new file mode 100644 index 000000000..5a80c3460 --- /dev/null +++ b/include/Nazara/Utility/Algorithm.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2013 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ALGORITHM_UTILITY_HPP +#define NAZARA_ALGORITHM_UTILITY_HPP + +#include +#include +#include +#include +#include + +NAZARA_API void NzComputeCubeIndexVertexCount(const NzVector3ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount); +NAZARA_API void NzComputeCubicSphereIndexVertexCount(unsigned int subdivision, unsigned int* indexCount, unsigned int* vertexCount); +NAZARA_API void NzComputeIcoSphereIndexVertexCount(unsigned int recursionLevel, unsigned int* indexCount, unsigned int* vertexCount); +NAZARA_API void NzComputePlaneIndexVertexCount(const NzVector2ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount); +NAZARA_API void NzComputeUvSphereIndexVertexCount(unsigned int sliceCount, unsigned int stackCount, unsigned int* indexCount, unsigned int* vertexCount); + +///TODO: Itérateur sur les indices +NAZARA_API void NzGenerateCube(const NzCubef& cube, const NzVector3ui& subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0); +NAZARA_API void NzGenerateCubicSphere(float size, unsigned int subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0); +NAZARA_API void NzGenerateIcoSphere(float size, unsigned int recursionLevel, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0); +NAZARA_API void NzGeneratePlane(const NzVector2ui& subdivision, const NzVector3f& position, const NzVector3f& normal, const NzVector2f& size, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0); +NAZARA_API void NzGenerateUvSphere(float size, unsigned int sliceCount, unsigned int stackCount, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0); + +inline void NzTransformVertex(NzMeshVertex* vertex, const NzMatrix4f& matrix); +inline void NzTransformVertices(NzMeshVertex* vertices, unsigned int vertexCount, const NzMatrix4f& matrix); + +#include + +#endif // NAZARA_ALGORITHM_UTILITY_HPP diff --git a/include/Nazara/Utility/Algorithm.inl b/include/Nazara/Utility/Algorithm.inl new file mode 100644 index 000000000..b08d09227 --- /dev/null +++ b/include/Nazara/Utility/Algorithm.inl @@ -0,0 +1,24 @@ +// Copyright (C) 2013 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +void NzTransformVertex(NzMeshVertex* vertex, const NzMatrix4f& matrix) +{ + vertex->normal = matrix.Transform(vertex->normal, 0.f); + vertex->position = matrix.Transform(vertex->position); + vertex->tangent = matrix.Transform(vertex->tangent, 0.f); + vertex++; +} + +void NzTransformVertices(NzMeshVertex* vertices, unsigned int vertexCount, const NzMatrix4f& matrix) +{ + if (matrix.IsIdentity()) + return; + + for (unsigned int i = 0; i < vertexCount; ++i) + NzTransformVertex(vertices++, matrix); +} + +#include diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index dae845835..986319e4b 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -33,6 +33,7 @@ struct NAZARA_API NzMeshParams }; class NzAnimation; +class NzPrimitiveList; class NzMesh; typedef NzVertexStruct_XYZ_Normal_UV_Tangent NzMeshVertex; @@ -54,6 +55,8 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener bool AddSubMesh(NzSubMesh* subMesh); bool AddSubMesh(const NzString& identifier, NzSubMesh* subMesh); + void Build(const NzPrimitiveList& list, const NzMeshParams& params = NzMeshParams()); + bool CreateSkeletal(unsigned int jointCount); bool CreateStatic(); void Destroy(); diff --git a/src/Nazara/Utility/Algorithm.cpp b/src/Nazara/Utility/Algorithm.cpp new file mode 100644 index 000000000..7a818519a --- /dev/null +++ b/src/Nazara/Utility/Algorithm.cpp @@ -0,0 +1,396 @@ +// Copyright (C) 2013 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace +{ + class IcoSphereBuilder + { + public: + IcoSphereBuilder(const NzMatrix4f& matrix) : + m_matrix(matrix) + { + } + + void Generate(float size, unsigned int recursionLevel, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset) + { + // Grandement inspiré de http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html + const float t = (1.f + 2.236067f)/2.f; + + m_cache.clear(); + m_size = size; + m_vertices = vertices; + m_vertexIndex = 0; + + // Sommets de base + AddVertex({-1.f, t, 0.f}); + AddVertex({ 1.f, t, 0.f}); + AddVertex({-1.f, -t, 0.f}); + AddVertex({ 1.f, -t, 0.f}); + + AddVertex({0.f, -1.f, t}); + AddVertex({0.f, 1.f, t}); + AddVertex({0.f, -1.f, -t}); + AddVertex({0.f, 1.f, -t}); + + AddVertex({ t, 0.f, -1.f}); + AddVertex({ t, 0.f, 1.f}); + AddVertex({-t, 0.f, -1.f}); + AddVertex({-t, 0.f, 1.f}); + + std::vector triangles; + triangles.reserve(20 * NzIntegralPow(4, recursionLevel)); + + // Cinq triangles autour du premier point + triangles.push_back({0, 11, 5}); + triangles.push_back({0, 5, 1}); + triangles.push_back({0, 1, 7}); + triangles.push_back({0, 7, 10}); + triangles.push_back({0, 10, 11}); + + // Cinq faces adjaçentes + triangles.push_back({ 1, 5, 9}); + triangles.push_back({ 5, 11, 4}); + triangles.push_back({11, 10, 2}); + triangles.push_back({10, 7, 6}); + triangles.push_back({ 7, 1, 8}); + + // Cinq triangles autour du troisième point + triangles.push_back({3, 9, 4}); + triangles.push_back({3, 4, 2}); + triangles.push_back({3, 2, 6}); + triangles.push_back({3, 6, 8}); + triangles.push_back({3, 8, 9}); + + // Cinq faces adjaçentes + triangles.push_back({4, 9, 5}); + triangles.push_back({2, 4, 11}); + triangles.push_back({6, 2, 10}); + triangles.push_back({8, 6, 7}); + triangles.push_back({9, 8, 1}); + + // Et maintenant on affine la sphère + for (unsigned int i = 0; i < recursionLevel; ++i) + { + for (NzVector3ui& triangle : triangles) + { + unsigned int a = GetMiddleVertex(triangle.x, triangle.y); + unsigned int b = GetMiddleVertex(triangle.y, triangle.z); + unsigned int c = GetMiddleVertex(triangle.z, triangle.x); + + triangles.push_back({triangle.x, a, c}); + triangles.push_back({triangle.y, b, a}); + triangles.push_back({triangle.z, c, b}); + + triangle.Set(a, b, c); // Réutilisation du triangle + } + } + + for (const NzVector3ui& triangle : triangles) + { + *indices++ = triangle.x + indexOffset; + *indices++ = triangle.y + indexOffset; + *indices++ = triangle.z + indexOffset; + } + + if (aabb) + { + NzVector3f totalSize = size * m_matrix.GetScale(); + aabb->Set(-totalSize, totalSize); + } + } + + unsigned int AddVertex(const NzVector3f& position) + { + NzMeshVertex& vertex = m_vertices[m_vertexIndex]; + + vertex.normal = NzVector3f::Normalize(m_matrix.Transform(position, 0.f)); + vertex.position = m_matrix.Transform(m_size * position.GetNormal()); + + return m_vertexIndex++; + } + + unsigned int GetMiddleVertex(unsigned int index1, unsigned int index2) + { + nzUInt64 key = (static_cast(std::min(index1, index2)) << 32) + static_cast(std::max(index1, index2)); + auto it = m_cache.find(key); + if (it != m_cache.end()) + return it->second; + + NzVector3f middle = NzVector3f::Lerp(m_vertices[index1].position, m_vertices[index2].position, 0.5f); + + unsigned int index = AddVertex(middle); + m_cache[key] = index; + + return index; + } + + private: + std::unordered_map m_cache; + const NzMatrix4f& m_matrix; + NzMeshVertex* m_vertices; + float m_size; + unsigned int m_vertexIndex; + }; +} + +void NzComputeCubeIndexVertexCount(const NzVector3ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount) +{ + unsigned int xIndexCount, yIndexCount, zIndexCount; + unsigned int xVertexCount, yVertexCount, zVertexCount; + + NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.y, subdivision.z), &xIndexCount, &xVertexCount); + NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.z), &yIndexCount, &yVertexCount); + NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.y), &zIndexCount, &zVertexCount); + + if (indexCount) + *indexCount = xIndexCount*2 + yIndexCount*2 + zIndexCount*2; + + if (vertexCount) + *vertexCount = xVertexCount*2 + yVertexCount*2 + zVertexCount*2; +} + +void NzComputeCubicSphereIndexVertexCount(unsigned int subdivision, unsigned int* indexCount, unsigned int* vertexCount) +{ + // Comme tous nos plans sont identiques, on peut optimiser un peu + NzComputePlaneIndexVertexCount(NzVector2ui(subdivision), indexCount, vertexCount); + + if (indexCount) + *indexCount *= 6; + + if (vertexCount) + *vertexCount *= 6; +} + +void NzComputeIcoSphereIndexVertexCount(unsigned int recursionLevel, unsigned int* indexCount, unsigned int* vertexCount) +{ + if (indexCount) + *indexCount = 3 * 20 * NzIntegralPow(4, recursionLevel); + + if (vertexCount) + *vertexCount = NzIntegralPow(4, recursionLevel)*10 + 2; +} + +void NzComputePlaneIndexVertexCount(const NzVector2ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount) +{ + // Le nombre de faces appartenant à un axe est équivalent à 2 exposant la subdivision (2,3,5,9,17,33,...) + unsigned int horizontalFaceCount = (1 << subdivision.x); + unsigned int verticalFaceCount = (1 << subdivision.y); + + // Et le nombre de sommets est ce nombre ajouté de 1 + unsigned int horizontalVertexCount = horizontalFaceCount + 1; + unsigned int verticalVertexCount = verticalFaceCount + 1; + + if (indexCount) + *indexCount = horizontalFaceCount*verticalFaceCount*6; + + if (vertexCount) + *vertexCount = horizontalVertexCount*verticalVertexCount; +} + +void NzComputeUvSphereIndexVertexCount(unsigned int sliceCount, unsigned int stackCount, unsigned int* indexCount, unsigned int* vertexCount) +{ + if (indexCount) + *indexCount = (sliceCount-1) * (stackCount-1) * 6; + + if (vertexCount) + *vertexCount = sliceCount * stackCount; +} + +void NzGenerateCube(const NzCubef& cube, const NzVector3ui& subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset) +{ + unsigned int xIndexCount, yIndexCount, zIndexCount; + unsigned int xVertexCount, yVertexCount, zVertexCount; + + NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.y, subdivision.z), &xIndexCount, &xVertexCount); + NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.z), &yIndexCount, &yVertexCount); + NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.y), &zIndexCount, &zVertexCount); + + NzMeshVertex* oldVertices = vertices; + + // Face +X + NzGeneratePlane(NzVector2ui(subdivision.y, subdivision.z), cube.GetPosition() + NzVector3f::UnitX() * cube.width/2.f, NzVector3f::UnitX(), NzVector2f(cube.height, cube.depth), vertices, indices, nullptr, indexOffset); + indexOffset += xVertexCount; + indices += xIndexCount; + vertices += xVertexCount; + + // Face +Y + NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.z), cube.GetPosition() + NzVector3f::UnitY() * cube.height/2.f, NzVector3f::UnitY(), NzVector2f(cube.width, cube.depth), vertices, indices, nullptr, indexOffset); + indexOffset += yVertexCount; + indices += yIndexCount; + vertices += yVertexCount; + + // Face +Z + NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.y), cube.GetPosition() + NzVector3f::UnitZ() * cube.depth/2.f, NzVector3f::UnitZ(), NzVector2f(cube.width, cube.height), vertices, indices, nullptr, indexOffset); + indexOffset += zVertexCount; + indices += zIndexCount; + vertices += zVertexCount; + + // Face -X + NzGeneratePlane(NzVector2ui(subdivision.y, subdivision.z), cube.GetPosition() - NzVector3f::UnitX() * cube.width/2.f, -NzVector3f::UnitX(), NzVector2f(cube.height, cube.depth), vertices, indices, nullptr, indexOffset); + indexOffset += xVertexCount; + indices += xIndexCount; + vertices += xVertexCount; + + // Face -Y + NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.z), cube.GetPosition() - NzVector3f::UnitY() * cube.height/2.f, -NzVector3f::UnitY(), NzVector2f(cube.width, cube.depth), vertices, indices, nullptr, indexOffset); + indexOffset += yVertexCount; + indices += yIndexCount; + vertices += yVertexCount; + + // Face -Z + NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.y), cube.GetPosition() - NzVector3f::UnitZ() * cube.depth/2.f, -NzVector3f::UnitZ(), NzVector2f(cube.width, cube.height), vertices, indices, nullptr, indexOffset); + indexOffset += zVertexCount; + indices += zIndexCount; + vertices += zVertexCount; + + NzTransformVertices(oldVertices, vertices-oldVertices, matrix); + + if (aabb) + { + aabb->Set(NzVector3f::Unit()); + aabb->Transform(matrix, 0.f); + } +} + +void NzGenerateCubicSphere(float size, unsigned int subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset) +{ + unsigned int vertexCount; + NzComputeCubeIndexVertexCount(NzVector3ui(subdivision), nullptr, &vertexCount); + + // On envoie une matrice identité de sorte à ce que le cube ne subisse aucune transformation (rendant plus facile l'étape suivante) + NzGenerateCube(NzCubef(size, size, size), NzVector3ui(subdivision), NzMatrix4f::Identity(), vertices, indices, nullptr, indexOffset); + + if (aabb) + { + NzVector3f totalSize = size * matrix.GetScale(); + aabb->Set(-totalSize, totalSize); + } + + for (unsigned int i = 0; i < vertexCount; ++i) + { + vertices->normal = vertices->position.GetNormal(); + vertices->position = matrix.Transform(size * vertices->normal); + //vertices->tangent = ??? + vertices++; + } +} + +void NzGenerateIcoSphere(float size, unsigned int recursionLevel, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset) +{ + IcoSphereBuilder builder(matrix); + builder.Generate(size, recursionLevel, vertices, indices, aabb, indexOffset); +} + +void NzGeneratePlane(const NzVector2ui& subdivision, const NzVector3f& position, const NzVector3f& normal, const NzVector2f& size, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset) +{ + // Le nombre de faces appartenant à un axe est équivalent à 2 exposant la subdivision (2,3,5,9,17,33,...) + unsigned int horizontalFaceCount = (1 << subdivision.x); + unsigned int verticalFaceCount = (1 << subdivision.y); + + // Et le nombre de sommets est ce nombre ajouté de 1 + unsigned int horizontalVertexCount = horizontalFaceCount + 1; + unsigned int verticalVertexCount = verticalFaceCount + 1; + + // Pour plus de facilité, on va construire notre plan en considérant que la normale est de 0,1,0 + // et on va construire un quaternion représentant la rotation de cette normale à la normale demandée par l'utilisateur. + // Celui-ci, combiné avec la position, va former une transformation qu'il suffira d'appliquer aux sommets + NzQuaternionf rotation; + rotation.MakeRotationBetween(NzVector3f::UnitY(), normal); + + NzMatrix4f transform; + transform.MakeTransform(position, rotation); + + ///FIXME: Vérifier les tangentes + NzVector3f tangent(1.f, 1.f, 0.f); + tangent = rotation * tangent; + tangent.Normalize(); + + float halfSizeX = size.x / 2.f; + float halfSizeY = size.y / 2.f; + + float invHorizontalVertexCount = 1.f/(horizontalVertexCount-1); + float invVerticalVertexCount = 1.f/(verticalVertexCount-1); + for (unsigned int x = 0; x < horizontalVertexCount; ++x) + { + for (unsigned int y = 0; y < verticalVertexCount; ++y) + { + NzVector3f localPos((2.f*x*invHorizontalVertexCount - 1.f) * halfSizeX, 0.f, (2.f*y*invVerticalVertexCount - 1.f) * halfSizeY); + vertices->position = transform * localPos; + vertices->uv.Set(x*invHorizontalVertexCount, y*invVerticalVertexCount); + vertices->normal = normal; + vertices->tangent = tangent; + vertices++; + + if (x != horizontalVertexCount-1 && y != verticalVertexCount-1) + { + *indices++ = (x+0)*verticalVertexCount + y + 0 + indexOffset; + *indices++ = (x+0)*verticalVertexCount + y + 1 + indexOffset; + *indices++ = (x+1)*verticalVertexCount + y + 0 + indexOffset; + + *indices++ = (x+1)*verticalVertexCount + y + 0 + indexOffset; + *indices++ = (x+0)*verticalVertexCount + y + 1 + indexOffset; + *indices++ = (x+1)*verticalVertexCount + y + 1 + indexOffset; + } + } + } + + if (aabb) + aabb->Set(rotation * NzVector3f(-halfSizeX, 0.f, -halfSizeY), rotation * NzVector3f(halfSizeX, 0.f, halfSizeY)); +} + +void NzGenerateUvSphere(float size, unsigned int sliceCount, unsigned int stackCount, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset) +{ + // http://stackoverflow.com/questions/14080932/implementing-opengl-sphere-example-code + float invSliceCount = 1.f / (sliceCount-1); + float invStackCount = 1.f / (stackCount-1); + + const float pi = M_PI; // Pour éviter toute promotion en double + const float pi2 = pi * 2.f; + const float pi_2 = pi / 2.f; + + for (unsigned int stack = 0; stack < stackCount; ++stack) + { + float stackVal = stack * invStackCount; + float stackValPi = stackVal * pi; + float sinStackValPi = std::sin(stackValPi); + + for (unsigned int slice = 0; slice < sliceCount; ++slice) + { + float sliceVal = slice * invSliceCount; + float sliceValPi2 = sliceVal * pi2; + + NzVector3f normal; + normal.y = std::sin(-pi_2 + stackValPi); + normal.x = std::cos(sliceValPi2) * sinStackValPi; + normal.z = std::sin(sliceValPi2) * sinStackValPi; + + vertices->position = matrix.Transform(size * normal); + vertices->normal = matrix.Transform(normal, 0.f); + vertices->uv.Set(1.f - sliceVal, stackVal); + vertices++; + + if (stack != stackCount-1 && slice != sliceCount-1) + { + *indices++ = (stack+0)*sliceCount + (slice+0) + indexOffset; + *indices++ = (stack+1)*sliceCount + (slice+0) + indexOffset; + *indices++ = (stack+0)*sliceCount + (slice+1) + indexOffset; + + *indices++ = (stack+0)*sliceCount + (slice+1) + indexOffset; + *indices++ = (stack+1)*sliceCount + (slice+0) + indexOffset; + *indices++ = (stack+1)*sliceCount + (slice+1) + indexOffset; + } + } + } + + if (aabb) + { + NzVector3f totalSize = size * matrix.GetScale(); + aabb->Set(-totalSize, totalSize); + } +} diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index 8c3486600..3e5ffcc26 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -3,16 +3,24 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include +#include +#include +#include #include #include +#include #include +#include #include #include +#include #include #include -#include #include +#include +#include #include NzMeshParams::NzMeshParams() @@ -126,6 +134,218 @@ bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh) return true; } +void NzMesh::Build(const NzPrimitiveList& list, const NzMeshParams& params) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Mesh not created"); + return; + } + + if (m_impl->animationType != nzAnimationType_Static) + { + NazaraError("Mesh must be static"); + return; + } + #endif + + unsigned int primitiveCount = list.GetSize(); + + #if NAZARA_UTILITY_SAFE + if (primitiveCount == 0) + { + NazaraError("GeomBuilder has no primitive"); + return; + } + + if (!params.IsValid()) + { + NazaraError("Parameters must be valid"); + return; + } + #endif + + for (unsigned int p = 0; p < primitiveCount; ++p) + { + NzCubef aabb; + std::unique_ptr indexBuffer; + std::unique_ptr vertexBuffer; + + const NzPrimitive& primitive = list.GetPrimitive(p); + + switch (primitive.type) + { + case nzPrimitiveType_Cube: + { + unsigned int indexCount; + unsigned int vertexCount; + NzComputeCubeIndexVertexCount(primitive.cube.subdivision, &indexCount, &vertexCount); + + indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits::max(), params.storage, nzBufferUsage_Static)); + indexBuffer->SetPersistent(false); + + vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static)); + vertexBuffer->SetPersistent(false); + + ///TODO: Remplacer par un itérateur sur les indices + std::vector indices; + indices.resize(indexCount); + + NzBufferMapper vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); + NzGenerateCube(primitive.cube.cube, primitive.cube.subdivision, primitive.cube.matrix, static_cast(vertexMapper.GetPointer()), &indices[0], &aabb); + vertexMapper.Unmap(); + + NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); + + for (unsigned int i = 0; i < indexCount; ++i) + indexMapper.Set(i, indices[i]); + + indexMapper.Unmap(); + break; + } + + case nzPrimitiveType_Plane: + { + unsigned int indexCount; + unsigned int vertexCount; + NzComputePlaneIndexVertexCount(primitive.plane.subdivision, &indexCount, &vertexCount); + + indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits::max(), params.storage, nzBufferUsage_Static)); + indexBuffer->SetPersistent(false); + + vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static)); + vertexBuffer->SetPersistent(false); + + ///TODO: Remplacer par un itérateur sur les indices + std::vector indices; + indices.resize(indexCount); + + NzBufferMapper vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); + NzGeneratePlane(primitive.plane.subdivision, primitive.plane.position, primitive.plane.normal, primitive.plane.size, static_cast(vertexMapper.GetPointer()), &indices[0], &aabb); + vertexMapper.Unmap(); + + NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); + + for (unsigned int i = 0; i < indexCount; ++i) + indexMapper.Set(i, indices[i]); + + indexMapper.Unmap(); + break; + } + + case nzPrimitiveType_Sphere: + { + switch (primitive.sphere.type) + { + case nzSphereType_Cubic: + { + unsigned int indexCount; + unsigned int vertexCount; + NzComputeCubicSphereIndexVertexCount(primitive.sphere.cubic.subdivision, &indexCount, &vertexCount); + + indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits::max(), params.storage, nzBufferUsage_Static)); + indexBuffer->SetPersistent(false); + + vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static)); + vertexBuffer->SetPersistent(false); + + ///TODO: Remplacer par un itérateur sur les indices + std::vector indices; + indices.resize(indexCount); + + NzBufferMapper vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); + NzGenerateCubicSphere(primitive.sphere.size, primitive.sphere.cubic.subdivision, primitive.sphere.matrix, static_cast(vertexMapper.GetPointer()), &indices[0], &aabb); + vertexMapper.Unmap(); + + NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); + + for (unsigned int i = 0; i < indexCount; ++i) + indexMapper.Set(i, indices[i]); + + indexMapper.Unmap(); + break; + } + + case nzSphereType_Ico: + { + unsigned int indexCount; + unsigned int vertexCount; + NzComputeIcoSphereIndexVertexCount(primitive.sphere.ico.recursionLevel, &indexCount, &vertexCount); + + indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits::max(), params.storage, nzBufferUsage_Static)); + indexBuffer->SetPersistent(false); + + vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static)); + vertexBuffer->SetPersistent(false); + + ///TODO: Remplacer par un itérateur sur les indices + std::vector indices; + indices.resize(indexCount); + + NzBufferMapper vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); + NzGenerateIcoSphere(primitive.sphere.size, primitive.sphere.ico.recursionLevel, primitive.sphere.matrix, static_cast(vertexMapper.GetPointer()), &indices[0], &aabb); + vertexMapper.Unmap(); + + NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); + + for (unsigned int i = 0; i < indexCount; ++i) + indexMapper.Set(i, indices[i]); + + indexMapper.Unmap(); + break; + } + + case nzSphereType_UV: + { + unsigned int indexCount; + unsigned int vertexCount; + NzComputeUvSphereIndexVertexCount(primitive.sphere.uv.slices, primitive.sphere.uv.stacks, &indexCount, &vertexCount); + + indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits::max(), params.storage, nzBufferUsage_Static)); + indexBuffer->SetPersistent(false); + + vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static)); + vertexBuffer->SetPersistent(false); + + ///TODO: Remplacer par un itérateur sur les indices + std::vector indices; + indices.resize(indexCount); + + NzBufferMapper vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly); + NzGenerateUvSphere(primitive.sphere.size, primitive.sphere.uv.slices, primitive.sphere.uv.stacks, primitive.sphere.matrix, static_cast(vertexMapper.GetPointer()), &indices[0], &aabb); + vertexMapper.Unmap(); + + NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly); + + for (unsigned int i = 0; i < indexCount; ++i) + indexMapper.Set(i, indices[i]); + + indexMapper.Unmap(); + } + } + break; + } + } + + std::unique_ptr subMesh(new NzStaticMesh(this)); + if (!subMesh->Create(vertexBuffer.get())) + { + NazaraError("Failed to create StaticMesh"); + break; + } + vertexBuffer.release(); + + subMesh->SetIndexBuffer(indexBuffer.get()); + indexBuffer.release(); + + subMesh->SetAABB(aabb); + + if (AddSubMesh(subMesh.get())) + subMesh.release(); + } +} + bool NzMesh::CreateSkeletal(unsigned int jointCount) { Destroy();