// Copyright (C) 2017 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 namespace Nz { template CullingList::~CullingList() { OnCullingListRelease(this); } template std::size_t CullingList::Cull(const Frustumf& frustum, bool* forceInvalidation) { m_results.clear(); bool forcedInvalidation = false; std::size_t visibleHash = 0U; for (NoTestVisibilityEntry& entry : m_noTestList) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); if (entry.forceInvalidation) { forcedInvalidation = true; entry.forceInvalidation = false; } } for (SphereVisibilityEntry& entry : m_sphereTestList) { if (frustum.Contains(entry.sphere)) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); if (entry.forceInvalidation) { forcedInvalidation = true; entry.forceInvalidation = false; } } } for (VolumeVisibilityEntry& entry : m_volumeTestList) { if (frustum.Contains(entry.volume)) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); if (entry.forceInvalidation) { forcedInvalidation = true; entry.forceInvalidation = false; } } } if (forceInvalidation) *forceInvalidation = forcedInvalidation; return visibleHash; } template std::size_t CullingList::FillWithAllEntries() { m_results.clear(); std::size_t visibleHash = 0U; for (NoTestVisibilityEntry& entry : m_noTestList) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); } for (SphereVisibilityEntry& entry : m_sphereTestList) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); } for (VolumeVisibilityEntry& entry : m_volumeTestList) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); } return visibleHash; } template auto CullingList::RegisterNoTest(const T* renderable) -> NoTestEntry { NoTestEntry newEntry(this, m_volumeTestList.size()); m_noTestList.emplace_back(NoTestVisibilityEntry{&newEntry, renderable, false}); //< Address of entry will be updated when moving return newEntry; } template auto CullingList::RegisterSphereTest(const T* renderable) -> SphereEntry { SphereEntry newEntry(this, m_sphereTestList.size() - 1); m_sphereTestList.emplace_back(SphereVisibilityEntry{Nz::Spheref(), &newEntry, renderable, false}); //< Address of entry will be updated when moving return newEntry; } template auto CullingList::RegisterVolumeTest(const T* renderable) -> VolumeEntry { VolumeEntry newEntry(this, m_volumeTestList.size()); m_volumeTestList.emplace_back(VolumeVisibilityEntry{Nz::BoundingVolumef(), &newEntry, renderable, false}); //< Address of entry will be updated when moving return newEntry; } // Interface STD template typename CullingList::ResultContainer::iterator CullingList::begin() { return m_results.begin(); } template typename CullingList::ResultContainer::const_iterator CullingList::begin() const { return m_results.begin(); } template typename CullingList::ResultContainer::const_iterator CullingList::cbegin() const { return m_results.cbegin(); } template typename CullingList::ResultContainer::const_iterator CullingList::cend() const { return m_results.cend(); } template typename CullingList::ResultContainer::const_reverse_iterator CullingList::crbegin() const { return m_results.crbegin(); } template typename CullingList::ResultContainer::const_reverse_iterator CullingList::crend() const { return m_results.crend(); } template bool CullingList::empty() const { return m_results.empty(); } template typename CullingList::ResultContainer::iterator CullingList::end() { return m_results.end(); } template typename CullingList::ResultContainer::const_iterator CullingList::end() const { return m_results.end(); } template typename CullingList::ResultContainer::reverse_iterator CullingList::rbegin() { return m_results.rbegin(); } template typename CullingList::ResultContainer::const_reverse_iterator CullingList::rbegin() const { return m_results.rbegin(); } template typename CullingList::ResultContainer::reverse_iterator CullingList::rend() { return m_results.rend(); } template typename CullingList::ResultContainer::const_reverse_iterator CullingList::rend() const { return m_results.rend(); } template typename CullingList::ResultContainer::size_type CullingList::size() const { return m_results.size(); } template void CullingList::NotifyForceInvalidation(CullTest type, std::size_t index) { switch (type) { case CullTest::NoTest: { m_noTestList[index].forceInvalidation = true; break; } case CullTest::Sphere: { m_sphereTestList[index].forceInvalidation = true; break; } case CullTest::Volume: { m_volumeTestList[index].forceInvalidation = true; break; } default: NazaraInternalError("Unhandled culltype"); break; } } template void CullingList::NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr) { NazaraUnused(oldPtr); switch (type) { case CullTest::NoTest: { NoTestVisibilityEntry& entry = m_noTestList[index]; NazaraAssert(entry.entry == oldPtr, "Invalid entry"); entry.entry = static_cast(newPtr); break; } case CullTest::Sphere: { SphereVisibilityEntry& entry = m_sphereTestList[index]; NazaraAssert(entry.entry == oldPtr, "Invalid sphere entry"); entry.entry = static_cast(newPtr); break; } case CullTest::Volume: { VolumeVisibilityEntry& entry = m_volumeTestList[index]; NazaraAssert(entry.entry == oldPtr, "Invalid volume entry"); entry.entry = static_cast(newPtr); break; } default: NazaraInternalError("Unhandled culltype"); break; } } template void CullingList::NotifyRelease(CullTest type, std::size_t index) { switch (type) { case CullTest::NoTest: { m_noTestList[index] = std::move(m_noTestList.back()); m_noTestList[index].entry->UpdateIndex(index); m_noTestList.pop_back(); break; } case CullTest::Sphere: { m_sphereTestList[index] = std::move(m_sphereTestList.back()); m_sphereTestList[index].entry->UpdateIndex(index); m_sphereTestList.pop_back(); break; } case CullTest::Volume: { m_volumeTestList[index] = std::move(m_volumeTestList.back()); m_volumeTestList[index].entry->UpdateIndex(index); m_volumeTestList.pop_back(); break; } default: NazaraInternalError("Unhandled culltype"); break; } } template void CullingList::NotifySphereUpdate(std::size_t index, const Spheref& sphere) { m_sphereTestList[index].sphere = sphere; } template void CullingList::NotifyVolumeUpdate(std::size_t index, const BoundingVolumef& boundingVolume) { m_volumeTestList[index].volume = boundingVolume; } ////////////////////////////////////////////////////////////////////////// template template CullingList::Entry::Entry() : m_parent(nullptr) { } template template CullingList::Entry::Entry(CullingList* parent, std::size_t index) : m_index(index), m_parent(parent) { } template template CullingList::Entry::Entry(Entry&& entry) : m_index(entry.m_index), m_parent(entry.m_parent) { if (m_parent) m_parent->NotifyMovement(Type, m_index, &entry, this); entry.m_parent = nullptr; } template template CullingList::Entry::~Entry() { if (m_parent) m_parent->NotifyRelease(Type, m_index); } template template void CullingList::Entry::ForceInvalidation() { m_parent->NotifyForceInvalidation(Type, m_index); } template template CullingList* CullingList::Entry::GetParent() const { return m_parent; } template template void CullingList::Entry::UpdateIndex(std::size_t index) { m_index = index; } template template #ifdef NAZARA_COMPILER_MSVC // MSVC bug typename CullingList::Entry& CullingList::Entry::operator=(Entry&& entry) #else typename CullingList::template Entry& CullingList::Entry::operator=(Entry&& entry) #endif { m_index = entry.m_index; m_parent = entry.m_parent; if (m_parent) m_parent->NotifyMovement(Type, m_index, &entry, this); entry.m_parent = nullptr; return *this; } ////////////////////////////////////////////////////////////////////////// template CullingList::NoTestEntry::NoTestEntry() : Entry() { } template CullingList::NoTestEntry::NoTestEntry(CullingList* parent, std::size_t index) : Entry(parent, index) { } ////////////////////////////////////////////////////////////////////////// template CullingList::SphereEntry::SphereEntry() : Entry() { } template CullingList::SphereEntry::SphereEntry(CullingList* parent, std::size_t index) : Entry(parent, index) { } template void CullingList::SphereEntry::UpdateSphere(const Spheref& sphere) { this->m_parent->NotifySphereUpdate(this->m_index, sphere); } ////////////////////////////////////////////////////////////////////////// template CullingList::VolumeEntry::VolumeEntry() : Entry() { } template CullingList::VolumeEntry::VolumeEntry(CullingList* parent, std::size_t index) : Entry(parent, index) { } template void CullingList::VolumeEntry::UpdateVolume(const BoundingVolumef& volume) { this->m_parent->NotifyVolumeUpdate(this->m_index, volume); } } #include