From 0a7711d85bec7ae6e9d2678a80a44d28a0044091 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 23 Jan 2015 22:35:41 +0100 Subject: [PATCH] (Scene) Added CreateNode and Clear methods Former-commit-id: de92f4a4be45e5cbd1d2d83191300e0b46764f0e --- examples/FirstScene/main.cpp | 23 +++---- include/Nazara/Graphics/Scene.hpp | 13 ++++ include/Nazara/Graphics/Scene.inl | 107 ++++++++++++++++++++++++++++++ src/Nazara/Graphics/Scene.cpp | 29 +++++++- 4 files changed, 154 insertions(+), 18 deletions(-) create mode 100644 include/Nazara/Graphics/Scene.inl diff --git a/examples/FirstScene/main.cpp b/examples/FirstScene/main.cpp index 62a4425c8..9ed702a69 100644 --- a/examples/FirstScene/main.cpp +++ b/examples/FirstScene/main.cpp @@ -84,7 +84,7 @@ int main() // Ensuite, nous allons rajouter un modèle à notre scène. // Les modèles représentent, globalement, tout ce qui est visible en trois dimensions. // Nous choisirons ici un vaisseau spatial (Quoi de mieux pour une scène spatiale ?) - NzModel spaceship; + NzModel* spaceship = scene.CreateNode(); // Création depuis la scène // Une structure permettant de paramétrer le chargement des modèles NzModelParameters params; @@ -101,7 +101,7 @@ int main() // On charge ensuite le modèle depuis son fichier // Le moteur va charger le fichier et essayer de retrouver les fichiers associés (comme les matériaux, textures, ...) - if (!spaceship.LoadFromFile("resources/Spaceship/spaceship.obj", params)) + if (!spaceship->LoadFromFile("resources/Spaceship/spaceship.obj", params)) { std::cout << "Failed to load spaceship" << std::endl; std::getchar(); @@ -111,7 +111,7 @@ int main() // Nous voulons afficher quelques statistiques relatives au modèle, comme le nombre de sommets et de triangles // Pour cela, nous devons accéder au mesh (maillage 3D) - NzMesh* mesh = spaceship.GetMesh(); + NzMesh* mesh = spaceship->GetMesh(); std::cout << mesh->GetVertexCount() << " sommets" << std::endl; std::cout << mesh->GetTriangleCount() << " triangles" << std::endl; @@ -119,7 +119,7 @@ int main() // En revanche, le format OBJ ne précise pas l'utilisation d'une normal map, nous devons donc la charger manuellement // Pour commencer on récupère le matériau du mesh, celui-ci en possède plusieurs mais celui qui nous intéresse, // celui de la coque, est le second (Cela est bien entendu lié au modèle en lui-même) - NzMaterial* material = spaceship.GetMaterial(1); + NzMaterial* material = spaceship->GetMaterial(1); // On lui indique ensuite le chemin vers la normal map if (!material->SetNormalMap("resources/Spaceship/Texture/normal.png")) @@ -129,10 +129,6 @@ int main() std::cout << "Failed to load normal map" << std::endl; } - // Il nous reste à attacher le modèle à la scène, ce qui se fait simplement via cet appel - spaceship.SetParent(scene); - // Et voilà, à partir de maintenant le modèle fait partie de la hiérarchie de la scène, et sera donc rendu avec cette dernière - // Nous avons besoin également d'une caméra, pour des raisons évidentes, celle-ci sera à l'écart du modèle // regardant dans sa direction. @@ -164,18 +160,15 @@ int main() // -PointLight: Lumière située à un endroit précis, envoyant de la lumière finie dans toutes les directions // -SpotLight: Lumière située à un endroit précis, envoyant de la lumière vers un endroit donné, avec un angle de diffusion - // Nous choisissons une lumière directionnelle représentant la nébuleuse de notre skybox - NzLight nebulaLight(nzLightType_Directional); + // Nous créons une lumière directionnelle pour représenter la nébuleuse de notre skybox + NzLight* nebulaLight = scene.CreateNode(nzLightType_Directional); // Il nous faut ensuite configurer la lumière // Pour commencer, sa couleur, la nébuleuse étant d'une couleur jaune, j'ai choisi ces valeurs - nebulaLight.SetColor(NzColor(255, 182, 90)); + nebulaLight->SetColor(NzColor(255, 182, 90)); // Nous appliquons ensuite une rotation de sorte que la lumière dans la même direction que la nébuleuse - nebulaLight.SetRotation(NzEulerAnglesf(0.f, 102.f, 0.f)); - - // Et nous ajoutons la lumière à la scène - nebulaLight.SetParent(scene); + nebulaLight->SetRotation(NzEulerAnglesf(0.f, 102.f, 0.f)); // Nous allons maintenant créer la fenêtre, dans laquelle nous ferons nos rendus // Celle-ci demande des paramètres plus complexes diff --git a/include/Nazara/Graphics/Scene.hpp b/include/Nazara/Graphics/Scene.hpp index f317207c0..03b37bfc4 100644 --- a/include/Nazara/Graphics/Scene.hpp +++ b/include/Nazara/Graphics/Scene.hpp @@ -10,12 +10,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include class NzAbstractRenderQueue; @@ -37,6 +39,12 @@ class NAZARA_API NzScene void AddToVisibilityList(NzUpdatable* object); + template T* CreateNode(Args&&... args); + template T* CreateNode(const NzString& name, Args&&... args); + template T* CreateNode(const NzString& name, const NzString& templateNodeName); + + void Clear(); + void Cull(); void Draw(); @@ -78,10 +86,13 @@ class NAZARA_API NzScene operator const NzSceneNode&() const; private: + bool RegisterSceneNode(const NzString& name, NzSceneNode* node); void RecursiveFrustumCull(NzAbstractRenderQueue* renderQueue, const NzFrustumf& frustum, NzNode* node); mutable std::unique_ptr m_background; mutable std::unique_ptr m_renderTechnique; + std::unordered_map m_nodeMap; + std::vector> m_nodes; std::vector m_updateList; std::vector m_visibleUpdateList; NzClock m_updateClock; @@ -96,4 +107,6 @@ class NAZARA_API NzScene unsigned int m_updatePerSecond; }; +#include + #endif // NAZARA_SCENE_HPP diff --git a/include/Nazara/Graphics/Scene.inl b/include/Nazara/Graphics/Scene.inl new file mode 100644 index 000000000..3ac7be7af --- /dev/null +++ b/include/Nazara/Graphics/Scene.inl @@ -0,0 +1,107 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +///TODO: Déplacer vers SceneNode et exposer + +// Pour être sûr que ce code soit à jour +static_assert(nzSceneNodeType_Max == 6, "Please update the code below"); + +class NzLight; +class NzModel; +class NzParticleEmitter; +class NzSceneRoot; +class NzSprite; +class NzTextSprite; + +template +constexpr nzSceneNodeType NzImplGetType() +{ + return nzSceneNodeType_User; +} + +template<> +inline constexpr nzSceneNodeType NzImplGetType() +{ + return nzSceneNodeType_Light; +} + +template<> +inline constexpr nzSceneNodeType NzImplGetType() +{ + return nzSceneNodeType_Model; +} + +template<> +inline constexpr nzSceneNodeType NzImplGetType() +{ + return nzSceneNodeType_ParticleEmitter; +} + +template<> +inline constexpr nzSceneNodeType NzImplGetType() +{ + return nzSceneNodeType_Root; +} + +template<> +inline constexpr nzSceneNodeType NzImplGetType() +{ + return nzSceneNodeType_Sprite; +} + +template<> +inline constexpr nzSceneNodeType NzImplGetType() +{ + return nzSceneNodeType_TextSprite; +} + + +template +T* NzScene::CreateNode(Args&&... args) +{ + std::unique_ptr node(new T(std::forward(args)...)); + if (!RegisterSceneNode(NzString(), node.get())) + return nullptr; + + return node.release(); +} + +template +T* NzScene::CreateNode(const NzString& name, Args&&... args) +{ + std::unique_ptr node(new T(std::forward(args)...)); + if (!RegisterSceneNode(name, node.get())) + return nullptr; + + return node.release(); +} + +template +T* NzScene::CreateNode(const NzString& name, const NzString& templateNodeName) +{ + auto it = m_nodeMap.find(templateNodeName); + if (it == m_nodeMap.end()) + { + NazaraError("Node \"" + templateNodeName + "\" is not registred"); + return nullptr; + } + + NzSceneNode* sceneNode = it->second; + if (NzImplGetType() != sceneNode->GetSceneNodeType()) + { + NazaraError("Scene node type of T (" + NzString::Number(NzImplGetType()) + ") doesn't match template scene node type (" + NzString::Number(sceneNode->GetSceneNodeType()) + ")"); + return nullptr; + } + + std::unique_ptr node(static_cast(sceneNode)->Copy()); + if (!RegisterSceneNode(name, node.get())) + return nullptr; + + return node.release(); +} + +#include diff --git a/src/Nazara/Graphics/Scene.cpp b/src/Nazara/Graphics/Scene.cpp index 33624d6bd..4b86cdda5 100644 --- a/src/Nazara/Graphics/Scene.cpp +++ b/src/Nazara/Graphics/Scene.cpp @@ -29,6 +29,12 @@ void NzScene::AddToVisibilityList(NzUpdatable* object) m_visibleUpdateList.push_back(object); } +void NzScene::Clear() +{ + m_nodeMap.clear(); + m_nodes.clear(); +} + void NzScene::Cull() { #if NAZARA_GRAPHICS_SAFE @@ -48,8 +54,6 @@ void NzScene::Cull() RecursiveFrustumCull(renderQueue, m_viewer->GetFrustum(), &m_root); ///TODO: Occlusion culling - - ///TODO: Light culling } void NzScene::Draw() @@ -77,7 +81,7 @@ void NzScene::Draw() if (m_renderTechniqueRanking > 0) { m_renderTechnique.reset(NzRenderTechniques::GetByRanking(m_renderTechniqueRanking-1, &m_renderTechniqueRanking)); - NazaraError("Render technique \"" + oldName + "\" failed, fallback to \"" + m_renderTechnique->GetName() + '"'); + NazaraError("Render technique \"" + oldName + "\" failed, falling back to \"" + m_renderTechnique->GetName() + '"'); } else { @@ -333,6 +337,25 @@ NzScene::operator const NzSceneNode&() const return m_root; } +bool NzScene::RegisterSceneNode(const NzString& name, NzSceneNode* node) +{ + if (!name.IsEmpty()) + { + if (m_nodeMap.find(name) != m_nodeMap.end()) + { + NazaraError("Node " + name + " is already registred"); + return false; + } + + m_nodeMap[name] = node; + } + + node->SetParent(m_root, true); + + m_nodes.emplace_back(node); + return true; +} + void NzScene::RecursiveFrustumCull(NzAbstractRenderQueue* renderQueue, const NzFrustumf& frustum, NzNode* node) { for (NzNode* child : node->GetChilds())