Merge remote-tracking branch 'origin/3D-Engine'

Former-commit-id: 1781615fc780accbe6c11d55fd896038d97ffec9
This commit is contained in:
Lynix
2012-11-29 10:11:30 +01:00
27 changed files with 831 additions and 333 deletions

49
src/Nazara/3D/3D.cpp Normal file
View File

@@ -0,0 +1,49 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - 3D Module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/3D/3D.hpp>
#include <Nazara/3D/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/3D/Debug.hpp>
bool Nz3D::Initialize()
{
if (s_moduleReferenceCounter++ != 0)
return true; // Déjà initialisé
// Initialisation des dépendances
if (!NzRenderer::Initialize())
{
NazaraError("Failed to initialize renderer module");
return false;
}
// Initialisation du module
NazaraNotice("Initialized: 3D module");
return true;
}
bool Nz3D::IsInitialized()
{
return s_moduleReferenceCounter != 0;
}
void Nz3D::Uninitialize()
{
if (--s_moduleReferenceCounter != 0)
return; // Encore utilisé
// Libération du module
NazaraNotice("Uninitialized: 3D module");
// Libération des dépendances
NzRenderer::Uninitialize();
}
unsigned int Nz3D::s_moduleReferenceCounter = 0;

View File

@@ -20,7 +20,7 @@ void NzError(nzErrorType type, const NzString& error, unsigned int line, const c
#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
if (type == nzErrorType_AssertFailed)
exit(EXIT_FAILURE);
std::exit(EXIT_FAILURE);
#endif
}
@@ -56,7 +56,7 @@ NzString NzGetLastSystemError(unsigned int code)
return error;
#elif defined(NAZARA_PLATFORM_POSIX)
return strerror(code);
return std::strerror(code);
#else
#error GetLastSystemError is not implemented on this platform

View File

@@ -6,6 +6,8 @@
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Utility/VertexDeclaration.hpp>
#include <typeinfo>
#include <Nazara/Core/Debug.hpp>
NzResource::NzResource(bool persistent) :
@@ -111,13 +113,13 @@ void NzResource::RemoveResourceReference() const
}
}
void NzResource::SetPersistent(bool persistent)
void NzResource::SetPersistent(bool persistent, bool checkReferenceCount)
{
NazaraMutexLock(m_mutex);
m_resourcePersistent = persistent;
if (!persistent && m_resourceReferenceCount == 0)
if (checkReferenceCount && !persistent && m_resourceReferenceCount == 0)
{
NazaraMutexUnlock(m_mutex);
delete this;

View File

@@ -0,0 +1,15 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_LOADERS_TEXTURE_HPP
#define NAZARA_LOADERS_TEXTURE_HPP
#include <Nazara/Prerequesites.hpp>
void NzLoaders_Texture_Register();
void NzLoaders_Texture_Unregister();
#endif // NAZARA_LOADERS_TEXTURE_HPP

View File

@@ -0,0 +1,48 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/Loaders/Texture.hpp>
#include <Nazara/Renderer/Material.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Utility/Debug.hpp>
namespace
{
bool Check(NzInputStream& stream, const NzMaterialParams& parameters)
{
NazaraUnused(stream);
NazaraUnused(parameters);
return true; ///FIXME: Pas bon
}
bool Load(NzMaterial* material, NzInputStream& stream, const NzMaterialParams& parameters)
{
NazaraUnused(parameters);
NzTexture* texture = new NzTexture;
if (!texture->LoadFromStream(stream))
{
NazaraError("Failed to load diffuse map");
return false;
}
material->Reset();
material->SetDiffuseMap(texture);
texture->SetPersistent(false);
return true;
}
}
void NzLoaders_Texture_Register()
{
///FIXME: Pas bon
NzMaterialLoader::RegisterLoader("bmp,gif,hdr,jpg,jpeg,pic,png,psd,tga", Check, Load);
}
void NzLoaders_Texture_Unregister()
{
NzMaterialLoader::UnregisterLoader("bmp,gif,hdr,jpg,jpeg,pic,png,psd,tga", Check, Load);
}

View File

@@ -0,0 +1,238 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/Material.hpp>
bool NzMaterialParams::IsValid() const
{
return true;
}
NzMaterial::NzMaterial() :
m_diffuseMap(nullptr),
m_specularMap(nullptr)
{
Reset();
}
NzMaterial::~NzMaterial()
{
if (m_diffuseMap)
m_diffuseMap->RemoveResourceReference();
if (m_specularMap)
m_specularMap->RemoveResourceReference();
}
void NzMaterial::EnableAlphaBlending(bool alphaBlending)
{
m_alphaBlendingEnabled = alphaBlending;
}
void NzMaterial::EnableZTest(bool zTest)
{
m_zTestEnabled = zTest;
}
void NzMaterial::EnableZWrite(bool zWrite)
{
m_zWriteEnabled = zWrite;
}
NzColor NzMaterial::GetAmbientColor() const
{
return m_ambientColor;
}
NzColor NzMaterial::GetDiffuseColor() const
{
return m_diffuseColor;
}
const NzTexture* NzMaterial::GetDiffuseMap() const
{
return m_diffuseMap;
}
nzBlendFunc NzMaterial::GetDstAlpha() const
{
return m_dstAlpha;
}
nzFaceCulling NzMaterial::GetFaceCulling() const
{
return m_faceCulling;
}
nzFaceFilling NzMaterial::GetFaceFilling() const
{
return m_faceFilling;
}
float NzMaterial::GetShininess() const
{
return m_shininess;
}
NzColor NzMaterial::GetSpecularColor() const
{
return m_specularColor;
}
const NzTexture* NzMaterial::GetSpecularMap() const
{
return m_specularMap;
}
nzBlendFunc NzMaterial::GetSrcAlpha() const
{
return m_srcAlpha;
}
nzRendererComparison NzMaterial::GetZTestCompare() const
{
return m_zTestCompareFunc;
}
bool NzMaterial::IsAlphaBlendingEnabled() const
{
return m_alphaBlendingEnabled;
}
bool NzMaterial::IsZTestEnabled() const
{
return m_zTestEnabled;
}
bool NzMaterial::IsZWriteEnabled() const
{
return m_zWriteEnabled;
}
bool NzMaterial::LoadFromFile(const NzString& filePath, const NzMaterialParams& params)
{
return NzMaterialLoader::LoadFromFile(this, filePath, params);
}
bool NzMaterial::LoadFromMemory(const void* data, std::size_t size, const NzMaterialParams& params)
{
return NzMaterialLoader::LoadFromMemory(this, data, size, params);
}
bool NzMaterial::LoadFromStream(NzInputStream& stream, const NzMaterialParams& params)
{
return NzMaterialLoader::LoadFromStream(this, stream, params);
}
void NzMaterial::Reset()
{
if (m_diffuseMap)
{
m_diffuseMap->RemoveResourceReference();
m_diffuseMap = nullptr;
}
if (m_specularMap)
{
m_specularMap->RemoveResourceReference();
m_specularMap = nullptr;
}
m_alphaBlendingEnabled = false;
m_ambientColor = NzColor::Black;
m_diffuseColor = NzColor::White;
m_dstAlpha = nzBlendFunc_Zero;
m_faceCulling = nzFaceCulling_Back;
m_faceFilling = nzFaceFilling_Fill;
m_shininess = 0;
m_specularColor = NzColor::White;
m_srcAlpha = nzBlendFunc_One;
m_zTestCompareFunc = nzRendererComparison_LessOrEqual;
m_zTestEnabled = true;
m_zWriteEnabled = true;
}
void NzMaterial::SetAmbientColor(const NzColor& ambient)
{
m_ambientColor = ambient;
}
void NzMaterial::SetDiffuseColor(const NzColor& diffuse)
{
m_diffuseColor = diffuse;
}
void NzMaterial::SetDiffuseMap(const NzTexture* map)
{
if (m_diffuseMap)
m_diffuseMap->RemoveResourceReference();
m_diffuseMap = map;
if (m_diffuseMap)
m_diffuseMap->AddResourceReference();
}
void NzMaterial::SetDstAlpha(nzBlendFunc func)
{
m_dstAlpha = func;
}
void NzMaterial::SetFaceCulling(nzFaceCulling culling)
{
m_faceCulling = culling;
}
void NzMaterial::SetFaceFilling(nzFaceFilling filling)
{
m_faceFilling = filling;
}
void NzMaterial::SetShininess(float shininess)
{
m_shininess = shininess;
}
void NzMaterial::SetSpecularColor(const NzColor& specular)
{
m_specularColor = specular;
}
void NzMaterial::SetSpecularMap(const NzTexture* map)
{
if (m_specularMap)
m_specularMap->RemoveResourceReference();
m_specularMap = map;
if (m_specularMap)
m_specularMap->AddResourceReference();
}
void NzMaterial::SetSrcAlpha(nzBlendFunc func)
{
m_srcAlpha = func;
}
void NzMaterial::SetZTestCompare(nzRendererComparison compareFunc)
{
m_zTestEnabled = compareFunc;
}
const NzMaterial* NzMaterial::GetDefault()
{
static NzMaterial defaultMaterial;
static bool initialized = false;
if (!initialized)
{
defaultMaterial.SetFaceCulling(nzFaceCulling_FrontAndBack);
defaultMaterial.SetFaceFilling(nzFaceFilling_Line);
defaultMaterial.SetDiffuseColor(NzColor::White);
initialized = true;
}
return &defaultMaterial;
}
NzMaterialLoader::LoaderList NzMaterial::s_loaders;

View File

@@ -14,6 +14,7 @@
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/Shader.hpp>
#include <Nazara/Renderer/ShaderImpl.hpp>
#include <Nazara/Renderer/Loaders/Texture.hpp>
#include <Nazara/Utility/BufferImpl.hpp>
#include <Nazara/Utility/IndexBuffer.hpp>
#include <Nazara/Utility/Utility.hpp>
@@ -449,6 +450,9 @@ bool NzRenderer::Initialize()
NazaraWarning("Failed to initialize debug drawer");
#endif
// Loaders
NzLoaders_Texture_Register();
NazaraNotice("Initialized: Renderer module");
return true;
@@ -903,6 +907,9 @@ void NzRenderer::Uninitialize()
if (--s_moduleReferenceCounter != 0)
return; // Encore utilisé
// Loaders
NzLoaders_Texture_Unregister();
#ifdef NAZARA_DEBUG
NzDebugDrawer::Uninitialize();
#endif
@@ -1065,11 +1072,11 @@ bool NzRenderer::EnsureStateUpdate()
glEnableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
glVertexAttribPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetElementCount(element->type),
NzOpenGL::ElementType[element->type],
(element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE,
stride,
&buffer[element->offset]);
NzVertexDeclaration::GetElementCount(element->type),
NzOpenGL::ElementType[element->type],
(element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE,
stride,
&buffer[element->offset]);
}
else
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);

View File

@@ -4,6 +4,7 @@
#include <Nazara/Utility/KeyframeMesh.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Animation.hpp>
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <vector>
@@ -222,16 +223,22 @@ const NzVertexBuffer* NzKeyframeMesh::GetVertexBuffer() const
return m_impl->vertexBuffer;
}
void NzKeyframeMesh::Interpolate(unsigned int frameA, unsigned int frameB, float interpolation) const
void NzKeyframeMesh::Interpolate(const NzAnimation* animation, unsigned int frameA, unsigned int frameB, float interpolation) const
{
#if NAZARA_UTILITY_SAFE
if (!m_parent->HasAnimation())
if (!animation || !animation->IsValid())
{
NazaraError("Parent mesh has no animation");
NazaraError("Animation must be valid");
return;
}
unsigned int frameCount = m_parent->GetFrameCount();
if (animation->GetType() != nzAnimationType_Keyframe)
{
NazaraError("Animation must be of keyframe type");
return;
}
unsigned int frameCount = animation->GetFrameCount();
if (frameA >= frameCount)
{
NazaraError("Frame A is out of range (" + NzString::Number(frameA) + " >= " + NzString::Number(frameCount) + ')');

View File

@@ -8,6 +8,7 @@
#include <Nazara/Core/InputStream.hpp>
#include <Nazara/Math/Basic.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Utility/Animation.hpp>
#include <Nazara/Utility/KeyframeMesh.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Utility/Loaders/MD2/Constants.hpp>
@@ -18,7 +19,8 @@
namespace
{
bool Check(NzInputStream& stream, const NzMeshParams& parameters)
/// Loader de mesh
bool CheckMesh(NzInputStream& stream, const NzMeshParams& parameters)
{
NazaraUnused(parameters);
@@ -34,7 +36,7 @@ namespace
return magic[0] == md2Ident && magic[1] == 8;
}
bool Load(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters)
bool LoadMesh(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters)
{
md2_header header;
if (stream.Read(&header, sizeof(md2_header)) != sizeof(md2_header))
@@ -69,11 +71,8 @@ namespace
/// Création du mesh
// Animé ou statique, c'est la question
unsigned int startFrame = NzClamp(parameters.animation.startFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
unsigned int endFrame = NzClamp(parameters.animation.endFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
bool animated = (parameters.animated && startFrame != endFrame);
if (animated)
///FIXME: Le loader ne traite pas correctement le cas d'un mesh statique
if (parameters.animated)
mesh->CreateKeyframe();
else
mesh->CreateStatic();
@@ -84,9 +83,12 @@ namespace
return false;
}
mesh->SetAnimation(stream.GetPath()); // Même fichier
/// Chargement des skins
if (header.num_skins > 0)
{
mesh->SetMaterialCount(header.num_skins);
stream.SetCursorPos(header.offset_skins);
{
NzString baseDir = stream.GetDirectory();
@@ -94,90 +96,19 @@ namespace
for (unsigned int i = 0; i < header.num_skins; ++i)
{
stream.Read(skin, 68*sizeof(char));
mesh->AddMaterial(baseDir + skin);
mesh->SetMaterial(i, baseDir + skin);
}
}
}
/// Chargement des animations
if (animated)
{
NzAnimation* animation = new NzAnimation;
if (animation->CreateKeyframe(endFrame-startFrame+1))
{
// Décodage des séquences
///TODO: Optimiser le calcul
char last[16];
stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + 2*sizeof(NzVector3f));
stream.Read(last, 16*sizeof(char));
int pos = std::strlen(last)-1;
for (unsigned int j = 0; j < 2; ++j)
{
if (!std::isdigit(last[pos]))
break;
pos--;
}
last[pos+1] = '\0';
NzSequence sequence;
sequence.firstFrame = startFrame;
sequence.frameCount = 0;
sequence.frameRate = 10; // Par défaut pour les animations MD2
sequence.name = last;
char name[16];
for (unsigned int i = startFrame; i <= endFrame; ++i)
{
stream.SetCursorPos(header.offset_frames + i*header.framesize + 2*sizeof(NzVector3f));
stream.Read(name, 16*sizeof(char));
pos = std::strlen(name)-1;
for (unsigned int j = 0; j < 2; ++j)
{
if (!std::isdigit(name[pos]))
break;
pos--;
}
name[pos+1] = '\0';
if (std::strcmp(name, last) != 0) // Si les deux frames n'ont pas le même nom
{
std::strcpy(last, name);
// Alors on enregistre la séquence actuelle
animation->AddSequence(sequence);
// Et on initialise la séquence suivante
sequence.firstFrame = i;
sequence.frameCount = 0;
sequence.name = last;
}
sequence.frameCount++;
}
// On ajoute la dernière frame (Qui n'a pas été traitée par la boucle)
animation->AddSequence(sequence);
mesh->SetAnimation(animation);
animation->SetPersistent(false);
}
else
NazaraInternalError("Failed to create animaton");
}
/// Chargement des submesh
// Actuellement le loader ne charge qu'un submesh
// TODO: Utiliser les commandes OpenGL pour créer des indices et accélérer le rendu
unsigned int frameCount = endFrame - startFrame + 1;
unsigned int vertexCount = header.num_tris * 3;
std::unique_ptr<NzVertexBuffer> vertexBuffer(new NzVertexBuffer(NzMesh::GetDeclaration(), vertexCount, parameters.storage, nzBufferUsage_Dynamic));
std::unique_ptr<NzKeyframeMesh> subMesh(new NzKeyframeMesh(mesh));
if (!subMesh->Create(vertexBuffer.get(), frameCount))
if (!subMesh->Create(vertexBuffer.get(), header.num_frames))
{
NazaraError("Failed to create SubMesh");
return false;
@@ -222,13 +153,13 @@ namespace
#endif
/// Chargement des frames
stream.SetCursorPos(header.offset_frames + header.framesize*startFrame);
stream.SetCursorPos(header.offset_frames);
// Pour que le modèle soit correctement aligné, on génère un quaternion que nous appliquerons à chacune des vertices
NzQuaternionf rotationQuat = NzEulerAnglesf(-90.f, 90.f, 0.f);
md2_vertex* vertices = new md2_vertex[header.num_vertices];
for (unsigned int f = 0; f < frameCount; ++f)
for (unsigned int f = 0; f < header.num_frames; ++f)
{
NzVector3f scale, translate;
@@ -286,14 +217,125 @@ namespace
return true;
}
/// Loader d'animations
bool CheckAnim(NzInputStream& stream, const NzAnimationParams& parameters)
{
NazaraUnused(parameters);
nzUInt32 magic[2];
if (stream.Read(&magic[0], 2*sizeof(nzUInt32)) != 2*sizeof(nzUInt32))
return false;
#ifdef NAZARA_BIG_ENDIAN
NzByteSwap(&magic[0], sizeof(nzUInt32));
NzByteSwap(&magic[1], sizeof(nzUInt32));
#endif
return magic[0] == md2Ident && magic[1] == 8;
}
bool LoadAnim(NzAnimation* animation, NzInputStream& stream, const NzAnimationParams& parameters)
{
md2_header header;
if (stream.Read(&header, sizeof(md2_header)) != sizeof(md2_header))
{
NazaraError("Failed to read header");
return false;
}
#ifdef NAZARA_BIG_ENDIAN
NzByteSwap(&header.framesize, sizeof(nzUInt32));
NzByteSwap(&header.num_frames, sizeof(nzUInt32));
NzByteSwap(&header.offset_frames, sizeof(nzUInt32));
NzByteSwap(&header.offset_end, sizeof(nzUInt32));
#endif
if (stream.GetSize() < header.offset_end)
{
NazaraError("Incomplete MD2 file");
return false;
}
unsigned int startFrame = std::min(parameters.startFrame, static_cast<unsigned int>(header.num_frames-1));
unsigned int endFrame = std::min(parameters.endFrame, static_cast<unsigned int>(header.num_frames-1));
unsigned int frameCount = endFrame - startFrame + 1;
if (!animation->CreateKeyframe(frameCount))
{
NazaraInternalError("Failed to create animaton");
return false;
}
// Décodage des séquences
///TODO: Optimiser le calcul
char last[16];
stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + 2*sizeof(NzVector3f));
stream.Read(last, 16*sizeof(char));
int pos = std::strlen(last)-1;
for (unsigned int j = 0; j < 2; ++j)
{
if (!std::isdigit(last[pos]))
break;
pos--;
}
last[pos+1] = '\0';
NzSequence sequence;
sequence.firstFrame = startFrame;
sequence.frameCount = 0;
sequence.frameRate = 10; // Par défaut pour les animations MD2
sequence.name = last;
char name[16];
for (unsigned int i = startFrame; i <= endFrame; ++i)
{
stream.SetCursorPos(header.offset_frames + i*header.framesize + 2*sizeof(NzVector3f));
stream.Read(name, 16*sizeof(char));
pos = std::strlen(name)-1;
for (unsigned int j = 0; j < 2; ++j)
{
if (!std::isdigit(name[pos]))
break;
pos--;
}
name[pos+1] = '\0';
if (std::strcmp(name, last) != 0) // Si les deux frames n'ont pas le même nom
{
std::strcpy(last, name);
// Alors on enregistre la séquence actuelle
animation->AddSequence(sequence);
// Et on initialise la séquence suivante
sequence.firstFrame = i;
sequence.frameCount = 0;
sequence.name = last;
}
sequence.frameCount++;
}
// On ajoute la dernière frame (Qui n'a pas été traitée par la boucle)
animation->AddSequence(sequence);
return true;
}
}
void NzLoaders_MD2_Register()
{
NzMeshLoader::RegisterLoader("md2", Check, Load);
NzAnimationLoader::RegisterLoader("md2", CheckAnim, LoadAnim);
NzMeshLoader::RegisterLoader("md2", CheckMesh, LoadMesh);
}
void NzLoaders_MD2_Unregister()
{
NzMeshLoader::UnregisterLoader("md2", Check, Load);
NzAnimationLoader::UnregisterLoader("md2", CheckAnim, LoadAnim);
NzMeshLoader::UnregisterLoader("md2", CheckMesh, LoadMesh);
}

View File

@@ -175,8 +175,11 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
joint->SetInverseBindMatrix(bindMatrix.InverseAffine());
}
for (const Mesh& md5Mesh : m_meshes)
mesh->SetMaterialCount(m_meshes.size());
for (unsigned int i = 0; i < m_meshes.size(); ++i)
{
const Mesh& md5Mesh = m_meshes[i];
void* ptr;
unsigned int indexCount = md5Mesh.triangles.size()*3;
unsigned int vertexCount = md5Mesh.vertices.size();
@@ -270,10 +273,10 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
vertexBuffer.release();
NzWeight* weights = subMesh->GetWeight();
for (unsigned int i = 0; i < weightCount; ++i)
for (unsigned int j = 0; j < weightCount; ++j)
{
weights->jointIndex = md5Mesh.weights[i].joint;
weights->weight = md5Mesh.weights[i].bias;
weights->jointIndex = md5Mesh.weights[j].joint;
weights->weight = md5Mesh.weights[j].bias;
weights++;
}
@@ -301,14 +304,8 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
}
// Material
if (!md5Mesh.shader.IsEmpty())
{
unsigned int skinIndex;
if (mesh->AddMaterial(baseDir + md5Mesh.shader, &skinIndex))
subMesh->SetMaterialIndex(skinIndex);
else
NazaraWarning("Failed to add mesh shader");
}
mesh->SetMaterial(i, baseDir + md5Mesh.shader);
subMesh->SetMaterialIndex(i);
if (!mesh->AddSubMesh(subMesh.get()))
{
@@ -320,18 +317,12 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
// Animation
// Il est peut-être éventuellement possible que la probabilité que l'animation ait le même nom soit non-nulle.
NzString animationPath = m_stream.GetPath();
if (!animationPath.IsEmpty())
NzString path = m_stream.GetPath();
if (!path.IsEmpty())
{
animationPath.Replace(".md5mesh", ".md5anim", -8, NzString::CaseInsensitive);
if (NzFile::Exists(animationPath))
{
std::unique_ptr<NzAnimation> animation(new NzAnimation);
if (animation->LoadFromFile(animationPath) && mesh->SetAnimation(animation.get()))
animation.release();
else
NazaraWarning("Failed to load mesh's animation");
}
path.Replace(".md5mesh", ".md5anim", -8, NzString::CaseInsensitive);
if (NzFile::Exists(path))
mesh->SetAnimation(path);
}
}
}
@@ -343,8 +334,9 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
return false;
}
for (const Mesh& md5Mesh : m_meshes)
for (unsigned int i = 0; i < m_meshes.size(); ++i)
{
const Mesh& md5Mesh = m_meshes[i];
void* ptr;
unsigned int indexCount = md5Mesh.triangles.size()*3;
unsigned int vertexCount = md5Mesh.vertices.size();
@@ -479,14 +471,8 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
indexBuffer.release();
// Material
if (!md5Mesh.shader.IsEmpty())
{
unsigned int skinIndex;
if (mesh->AddMaterial(baseDir + md5Mesh.shader, &skinIndex))
subMesh->SetMaterialIndex(skinIndex);
else
NazaraWarning("Failed to add mesh shader");
}
mesh->SetMaterial(i, baseDir + md5Mesh.shader);
subMesh->SetMaterialIndex(i);
if (!mesh->AddSubMesh(subMesh.get()))
{

View File

@@ -4,6 +4,7 @@
#include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Animation.hpp>
#include <Nazara/Utility/Buffer.hpp>
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/KeyframeMesh.hpp>
@@ -23,12 +24,6 @@ NzMeshParams::NzMeshParams()
bool NzMeshParams::IsValid() const
{
if (!animation.IsValid())
{
NazaraError("Invalid animation parameters");
return false;
}
if (!NzBuffer::IsSupported(storage))
{
NazaraError("Storage not supported");
@@ -46,7 +41,7 @@ struct NzMeshImpl
nzAnimationType animationType;
NzAxisAlignedBox aabb;
NzSkeleton skeleton; // Uniquement pour les animations squelettiques
const NzAnimation* animation = nullptr;
NzString animationPath;
unsigned int jointCount; // Uniquement pour les animations squelettiques
};
@@ -55,45 +50,6 @@ NzMesh::~NzMesh()
Destroy();
}
bool NzMesh::AddMaterial(const NzString& matPath, unsigned int* matIndex)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return false;
}
if (matPath.IsEmpty())
{
NazaraError("Material path is empty");
return false;
}
#endif
NzString path = NzFile::NormalizeSeparators(matPath);
for (unsigned int i = 0; i < m_impl->materials.size(); ++i)
{
if (m_impl->materials[i] == path) // Ce skin est-il déjà présent ?
{
if (matIndex)
*matIndex = i;
return true;
}
}
// Sinon on l'ajoute
if (matIndex)
*matIndex = m_impl->materials.size();
m_impl->materials.push_back(matPath);
return true;
}
bool NzMesh::AddSubMesh(NzSubMesh* subMesh)
{
#if NAZARA_UTILITY_SAFE
@@ -111,7 +67,7 @@ bool NzMesh::AddSubMesh(NzSubMesh* subMesh)
if (subMesh->GetAnimationType() != m_impl->animationType)
{
NazaraError("Submesh's animation type must match mesh animation type");
NazaraError("Submesh animation type must match mesh animation type");
return false;
}
#endif
@@ -154,7 +110,7 @@ bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh)
if (m_impl->animationType != subMesh->GetAnimationType())
{
NazaraError("Submesh's animation type must match mesh animation type");
NazaraError("Submesh animation type must match mesh animation type");
return false;
}
#endif
@@ -170,7 +126,7 @@ bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh)
return true;
}
void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolation) const
void NzMesh::Animate(const NzAnimation* animation, unsigned int frameA, unsigned int frameB, float interpolation) const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
@@ -179,13 +135,19 @@ void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolati
return;
}
if (!m_impl->animation)
if (!animation || !animation->IsValid())
{
NazaraError("Mesh has no animation");
NazaraError("Animation must be valid");
return;
}
unsigned int frameCount = m_impl->animation->GetFrameCount();
if (animation->GetType() != m_impl->animationType)
{
NazaraError("Animation type must match mesh animation type");
return;
}
unsigned int frameCount = animation->GetFrameCount();
if (frameA >= frameCount)
{
NazaraError("Frame A is out of range (" + NzString::Number(frameA) + " >= " + NzString::Number(frameCount) + ')');
@@ -213,12 +175,12 @@ void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolati
for (NzSubMesh* subMesh : m_impl->subMeshes)
{
NzKeyframeMesh* keyframeMesh = static_cast<NzKeyframeMesh*>(subMesh);
keyframeMesh->Interpolate(frameA, frameB, interpolation);
keyframeMesh->InterpolateImpl(frameA, frameB, interpolation);
}
break;
case nzAnimationType_Skeletal:
m_impl->animation->AnimateSkeleton(&m_impl->skeleton, frameA, frameB, interpolation);
animation->AnimateSkeleton(&m_impl->skeleton, frameA, frameB, interpolation);
for (NzSubMesh* subMesh : m_impl->subMeshes)
{
NzSkeletalMesh* skeletalMesh = static_cast<NzSkeletalMesh*>(subMesh);
@@ -282,9 +244,6 @@ void NzMesh::Destroy()
{
NotifyDestroy();
if (m_impl->animation)
m_impl->animation->RemoveResourceListener(this);
for (NzSubMesh* subMesh : m_impl->subMeshes)
subMesh->RemoveResourceListener(this);
@@ -312,17 +271,17 @@ const NzAxisAlignedBox& NzMesh::GetAABB() const
return m_impl->aabb;
}
const NzAnimation* NzMesh::GetAnimation() const
NzString NzMesh::GetAnimation() const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return nullptr;
return nzAnimationType_Static;
}
#endif
return m_impl->animation;
return m_impl->animationPath;
}
nzAnimationType NzMesh::GetAnimationType() const
@@ -338,25 +297,6 @@ nzAnimationType NzMesh::GetAnimationType() const
return m_impl->animationType;
}
unsigned int NzMesh::GetFrameCount() const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return 0;
}
if (!m_impl->animation)
{
NazaraError("Mesh has no animation");
return 0;
}
#endif
return m_impl->animation->GetFrameCount();
}
unsigned int NzMesh::GetJointCount() const
{
#if NAZARA_UTILITY_SAFE
@@ -596,32 +536,6 @@ void NzMesh::InvalidateAABB() const
m_impl->aabb.SetNull();
}
bool NzMesh::HasAnimation() const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return false;
}
#endif
return m_impl->animation != nullptr;
}
bool NzMesh::HasMaterial(unsigned int index) const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return false;
}
#endif
return index < m_impl->materials.size();
}
bool NzMesh::HasSubMesh(const NzString& identifier) const
{
#if NAZARA_UTILITY_SAFE
@@ -681,29 +595,6 @@ bool NzMesh::LoadFromStream(NzInputStream& stream, const NzMeshParams& params)
return NzMeshLoader::LoadFromStream(this, stream, params);
}
void NzMesh::RemoveMaterial(unsigned int index)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return;
}
if (index >= m_impl->materials.size())
{
NazaraError("Material index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->materials.size()) + ')');
return;
}
#endif
// On accède à l'itérateur correspondant à l'entrée #index
auto it = m_impl->materials.begin();
std::advance(it, index);
m_impl->materials.erase(it);
}
void NzMesh::RemoveSubMesh(const NzString& identifier)
{
#if NAZARA_UTILITY_SAFE
@@ -763,46 +654,58 @@ void NzMesh::RemoveSubMesh(unsigned int index)
m_impl->aabb.SetNull(); // On invalide l'AABB
}
bool NzMesh::SetAnimation(const NzAnimation* animation)
void NzMesh::SetAnimation(const NzString& animationPath)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return false;
}
if (m_impl->animationType == nzAnimationType_Static)
{
NazaraError("Static meshes cannot have animation");
return false;
return;
}
#endif
if (animation == m_impl->animation)
return true;
m_impl->animationPath = animationPath;
}
if (m_impl->animation)
m_impl->animation->RemoveResourceListener(this);
if (animation)
void NzMesh::SetMaterial(unsigned int matIndex, const NzString& materialPath)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
#if NAZARA_UTILITY_SAFE
if (animation->GetType() != m_impl->animationType)
{
NazaraError("Animation's type must match mesh animation type");
m_impl->animation = nullptr;
return false;
}
#endif
animation->AddResourceListener(this);
NazaraError("Mesh not created");
return;
}
m_impl->animation = animation;
if (matIndex >= m_impl->materials.size())
{
NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_impl->materials.size()));
return;
}
#endif
return true;
m_impl->materials[matIndex] = materialPath;
}
void NzMesh::SetMaterialCount(unsigned int matCount)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return;
}
#endif
m_impl->materials.resize(matCount);
#ifdef NAZARA_DEBUG
for (NzSubMesh* subMesh : m_impl->subMeshes)
{
unsigned int matIndex = subMesh->GetMaterialIndex();
if (matIndex >= matCount)
NazaraWarning("SubMesh " + NzString::Pointer(subMesh) + " material index is over mesh new material count (" + NzString::Number(matIndex) + " >= " + NzString::Number(matCount));
}
#endif
}
void NzMesh::Skin(const NzSkeleton* skeleton) const
@@ -858,30 +761,11 @@ const NzVertexDeclaration* NzMesh::GetDeclaration()
return &declaration;
}
void NzMesh::OnResourceCreated(const NzResource* resource, int index)
{
NazaraUnused(index);
if (resource == m_impl->animation)
{
#if NAZARA_UTILITY_SAFE
if (m_impl->animation->GetType() != m_impl->animationType)
{
NazaraError("Animation's type must match mesh animation type");
m_impl->animation->RemoveResourceListener(this);
m_impl->animation = nullptr;
}
#endif
}
}
void NzMesh::OnResourceReleased(const NzResource* resource, int index)
{
if (resource == m_impl->animation)
SetAnimation(nullptr);
else
RemoveSubMesh(index);
NazaraUnused(resource);
RemoveSubMesh(index);
}
NzMeshLoader::LoaderList NzMesh::s_loaders;

View File

@@ -101,7 +101,7 @@ NzVector3f NzNode::GetTranslation() const
return m_translation;
}
NzMatrix4f NzNode::GetTransformMatrix() const
const NzMatrix4f& NzNode::GetTransformMatrix() const
{
if (!m_matrixUpdated)
UpdateMatrix();

View File

@@ -29,7 +29,7 @@ nzPrimitiveType NzSubMesh::GetPrimitiveType() const
return m_primitiveType;
}
unsigned int NzSubMesh::GetSkinIndex() const
unsigned int NzSubMesh::GetMaterialIndex() const
{
return m_matIndex;
}