Merge remote-tracking branch 'origin/Scene-Update'

Former-commit-id: 4185e7a826476d3d5b4275b3900fe695bd791f3a
This commit is contained in:
Lynix
2015-01-25 16:35:18 +01:00
26 changed files with 620 additions and 354 deletions

View File

@@ -9,57 +9,36 @@
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/ColorBackground.hpp>
#include <Nazara/Graphics/RenderTechniques.hpp>
#include <Nazara/Graphics/SceneRoot.hpp>
#include <Nazara/Graphics/SkinningManager.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <functional>
#include <memory>
#include <set>
#include <vector>
#include <Nazara/Graphics/Debug.hpp>
struct NzSceneImpl
NzScene::NzScene() :
m_ambientColor(25, 25, 25),
m_root(this),
m_viewer(nullptr),
m_backgroundEnabled(true),
m_update(false),
m_updatePerSecond(60)
{
NzSceneImpl(NzScene* scene) :
root(scene)
{
}
std::unique_ptr<NzAbstractBackground> background;
std::unique_ptr<NzAbstractRenderTechnique> renderTechnique;
std::vector<NzUpdatable*> updateList;
std::vector<NzUpdatable*> visibleUpdateList;
NzClock updateClock;
NzColor ambientColor = NzColor(25,25,25);
NzSceneRoot root;
NzAbstractViewer* viewer = nullptr;
bool backgroundEnabled = true;
bool update = false;
float frameTime;
float updateTime;
int renderTechniqueRanking;
unsigned int updatePerSecond = 60;
};
NzScene::NzScene()
{
m_impl = new NzSceneImpl(this);
}
NzScene::~NzScene()
{
delete m_impl;
}
void NzScene::AddToVisibilityList(NzUpdatable* object)
{
m_impl->visibleUpdateList.push_back(object);
m_visibleUpdateList.push_back(object);
}
void NzScene::Clear()
{
m_nodeMap.clear();
m_nodes.clear();
}
void NzScene::Cull()
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return;
@@ -69,42 +48,40 @@ void NzScene::Cull()
NzAbstractRenderQueue* renderQueue = GetRenderTechnique()->GetRenderQueue();
renderQueue->Clear(false);
m_impl->visibleUpdateList.clear();
m_visibleUpdateList.clear();
// Frustum culling
RecursiveFrustumCull(renderQueue, m_impl->viewer->GetFrustum(), &m_impl->root);
RecursiveFrustumCull(renderQueue, m_viewer->GetFrustum(), &m_root);
///TODO: Occlusion culling
///TODO: Light culling
}
void NzScene::Draw()
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return;
}
#endif
m_impl->viewer->ApplyView();
m_viewer->ApplyView();
try
{
NzErrorFlags errFlags(nzErrorFlag_ThrowException);
m_impl->renderTechnique->Clear(this);
m_impl->renderTechnique->Draw(this);
NzErrorFlags errFlags(nzErrorFlag_ThrowException, true);
m_renderTechnique->Clear(this);
m_renderTechnique->Draw(this);
}
catch (const std::exception& e)
{
NzString oldName = m_impl->renderTechnique->GetName();
NzString oldName = m_renderTechnique->GetName();
if (m_impl->renderTechniqueRanking > 0)
if (m_renderTechniqueRanking > 0)
{
m_impl->renderTechnique.reset(NzRenderTechniques::GetByRanking(m_impl->renderTechniqueRanking-1, &m_impl->renderTechniqueRanking));
NazaraError("Render technique \"" + oldName + "\" failed, fallback to \"" + m_impl->renderTechnique->GetName() + '"');
m_renderTechnique.reset(NzRenderTechniques::GetByRanking(m_renderTechniqueRanking-1, &m_renderTechniqueRanking));
NazaraError("Render technique \"" + oldName + "\" failed, falling back to \"" + m_renderTechnique->GetName() + '"');
}
else
{
@@ -118,131 +95,154 @@ void NzScene::Draw()
void NzScene::EnableBackground(bool enable)
{
m_impl->backgroundEnabled = enable;
m_backgroundEnabled = enable;
}
NzSceneNode* NzScene::FindNode(const NzString& name)
{
auto it = m_nodeMap.find(name);
if (it == m_nodeMap.end())
return nullptr;
return it->second;
}
const NzSceneNode* NzScene::FindNode(const NzString& name) const
{
auto it = m_nodeMap.find(name);
if (it == m_nodeMap.end())
return nullptr;
return it->second;
}
NzColor NzScene::GetAmbientColor() const
{
return m_impl->ambientColor;
return m_ambientColor;
}
NzAbstractBackground* NzScene::GetBackground() const
{
if (!m_impl->background)
m_impl->background.reset(new NzColorBackground);
if (!m_background)
m_background.reset(new NzColorBackground);
return m_impl->background.get();
return m_background.get();
}
NzVector3f NzScene::GetBackward() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Backward();
}
#endif
return -m_impl->viewer->GetGlobalForward();
return -m_viewer->GetGlobalForward();
}
NzVector3f NzScene::GetDown() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Down();
}
#endif
return -m_impl->viewer->GetGlobalUp();
return -m_viewer->GetGlobalUp();
}
NzVector3f NzScene::GetForward() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Forward();
}
#endif
return m_impl->viewer->GetGlobalForward();
return m_viewer->GetGlobalForward();
}
NzVector3f NzScene::GetLeft() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Left();
}
#endif
return -m_impl->viewer->GetGlobalRight();
return -m_viewer->GetGlobalRight();
}
NzAbstractRenderTechnique* NzScene::GetRenderTechnique() const
{
if (!m_impl->renderTechnique)
m_impl->renderTechnique.reset(NzRenderTechniques::GetByRanking(-1, &m_impl->renderTechniqueRanking));
if (!m_renderTechnique)
m_renderTechnique.reset(NzRenderTechniques::GetByRanking(-1, &m_renderTechniqueRanking));
return m_impl->renderTechnique.get();
return m_renderTechnique.get();
}
NzVector3f NzScene::GetRight() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Right();
}
#endif
return m_impl->viewer->GetGlobalRight();
return m_viewer->GetGlobalRight();
}
NzSceneNode& NzScene::GetRoot() const
NzSceneNode& NzScene::GetRoot()
{
return m_impl->root;
return m_root;
}
const NzSceneNode& NzScene::GetRoot() const
{
return m_root;
}
NzAbstractViewer* NzScene::GetViewer() const
{
return m_impl->viewer;
return m_viewer;
}
NzVector3f NzScene::GetUp() const
{
#if NAZARA_GRAPHICS_SAFE
if (!m_impl->viewer)
if (!m_viewer)
{
NazaraError("No viewer");
return NzVector3f::Up();
}
#endif
return m_impl->viewer->GetGlobalUp();
return m_viewer->GetGlobalUp();
}
float NzScene::GetUpdateTime() const
{
return m_impl->updateTime;
return m_updateTime;
}
unsigned int NzScene::GetUpdatePerSecond() const
{
return m_impl->updatePerSecond;
return m_updatePerSecond;
}
bool NzScene::IsBackgroundEnabled() const
{
return m_impl->backgroundEnabled;
return m_backgroundEnabled;
}
void NzScene::RegisterForUpdate(NzUpdatable* object)
@@ -255,32 +255,76 @@ void NzScene::RegisterForUpdate(NzUpdatable* object)
}
#endif
m_impl->updateList.push_back(object);
m_updateList.push_back(object);
}
void NzScene::RemoveNode(NzSceneNode* node)
{
if (!node)
return;
// C'est moche mais je n'ai pas d'autre choix que d'utiliser un std::unique_ptr pour utiliser std::find
std::unique_ptr<NzSceneNode> ptr(node);
auto it = std::find(m_nodes.begin(), m_nodes.end(), ptr);
ptr.release();
if (it == m_nodes.end())
{
NazaraError("This scene node doesn't belong to this scene");
return;
}
NzString nodeName = node->GetName();
if (!nodeName.IsEmpty())
m_nodeMap.erase(nodeName);
m_nodes.erase(it);
}
void NzScene::RemoveNode(const NzString& name)
{
RemoveNode(FindNode(name));
}
void NzScene::RenderFrame()
{
try
{
NzErrorFlags errFlags(nzErrorFlag_ThrowException, true);
Update();
Cull();
UpdateVisible();
Draw();
}
catch (const std::exception& e)
{
NazaraError("Failed to render frame: " + NzString(e.what()));
}
}
void NzScene::SetAmbientColor(const NzColor& color)
{
m_impl->ambientColor = color;
m_ambientColor = color;
}
void NzScene::SetBackground(NzAbstractBackground* background)
{
m_impl->background.reset(background);
m_background.reset(background);
}
void NzScene::SetRenderTechnique(NzAbstractRenderTechnique* renderTechnique)
{
m_impl->renderTechnique.reset(renderTechnique);
m_renderTechnique.reset(renderTechnique);
}
void NzScene::SetViewer(NzAbstractViewer* viewer)
{
if (m_impl->viewer != viewer)
if (m_viewer != viewer)
{
m_impl->viewer = viewer;
m_viewer = viewer;
// Invalidation de tous les nodes de la scène (utile pour la régénération des sommets dépendant du viewer)
m_impl->root.InvalidateNode();
m_root.InvalidateNode();
}
}
@@ -291,7 +335,7 @@ void NzScene::SetViewer(NzAbstractViewer& viewer)
void NzScene::SetUpdatePerSecond(unsigned int updatePerSecond)
{
m_impl->updatePerSecond = updatePerSecond;
m_updatePerSecond = updatePerSecond;
}
void NzScene::UnregisterForUpdate(NzUpdatable* object)
@@ -304,20 +348,20 @@ void NzScene::UnregisterForUpdate(NzUpdatable* object)
}
#endif
auto it = std::find(m_impl->updateList.begin(), m_impl->updateList.end(), object);
if (it != m_impl->updateList.end())
m_impl->updateList.erase(it);
auto it = std::find(m_updateList.begin(), m_updateList.end(), object);
if (it != m_updateList.end())
m_updateList.erase(it);
}
void NzScene::Update()
{
m_impl->update = (m_impl->updatePerSecond == 0 || m_impl->updateClock.GetMilliseconds() > 1000/m_impl->updatePerSecond);
if (m_impl->update)
m_update = (m_updatePerSecond == 0 || m_updateClock.GetMilliseconds() > 1000/m_updatePerSecond);
if (m_update)
{
m_impl->updateTime = m_impl->updateClock.GetSeconds();
m_impl->updateClock.Restart();
m_updateTime = m_updateClock.GetSeconds();
m_updateClock.Restart();
for (NzUpdatable* updatable : m_impl->updateList)
for (NzUpdatable* updatable : m_updateList)
///TODO: Multihreading
updatable->Update();
}
@@ -327,16 +371,68 @@ void NzScene::UpdateVisible()
{
NzSkinningManager::Skin();
if (m_impl->update)
if (m_update)
{
for (NzUpdatable* node : m_impl->visibleUpdateList)
for (NzUpdatable* node : m_visibleUpdateList)
node->Update();
}
}
NzScene::operator const NzSceneNode&() const
{
return m_impl->root;
return m_root;
}
bool NzScene::ChangeNodeName(NzSceneNode* node, const NzString& newName)
{
#ifdef NAZARA_DEBUG
std::unique_ptr<NzSceneNode> ptr(node);
auto it = std::find(m_nodes.begin(), m_nodes.end(), ptr);
ptr.release();
if (it == m_nodes.end())
{
NazaraInternalError("Node isn't part of the scene");
return false;
}
#endif
if (!newName.IsEmpty())
{
auto pair = m_nodeMap.insert(std::make_pair(newName, node));
if (!pair.second)
{
NazaraError("Name \"" + newName + "\" is already in use");
return false;
}
}
NzString oldName = node->GetName();
if (!oldName.IsEmpty())
m_nodeMap.erase(oldName);
node->SetNameInternal(newName);
return true;
}
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->SetNameInternal(name);
node->SetParent(m_root, true);
m_nodes.emplace_back(node);
return true;
}
void NzScene::RecursiveFrustumCull(NzAbstractRenderQueue* renderQueue, const NzFrustumf& frustum, NzNode* node)