// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Development Kit" // For conditions of distribution and use, see copyright notice in Prerequesites.hpp #include #include #include #include namespace Ndk { /*! * \brief Constructs a GraphicsComponent object by copy semantic * * \param graphicsComponent GraphicsComponent to copy */ inline GraphicsComponent::GraphicsComponent(const GraphicsComponent& graphicsComponent) : Component(graphicsComponent), HandledObject(graphicsComponent), m_boundingVolume(graphicsComponent.m_boundingVolume), m_transformMatrix(graphicsComponent.m_transformMatrix), m_boundingVolumeUpdated(graphicsComponent.m_boundingVolumeUpdated), m_transformMatrixUpdated(graphicsComponent.m_transformMatrixUpdated) { m_renderables.reserve(graphicsComponent.m_renderables.size()); for (const Renderable& r : graphicsComponent.m_renderables) Attach(r.renderable, r.data.localMatrix, r.data.renderOrder); } inline void GraphicsComponent::AddToCullingList(GraphicsComponentCullingList* cullingList) const { m_volumeCullingEntries.emplace_back(VolumeCullingEntry{}); VolumeCullingEntry& entry = m_volumeCullingEntries.back(); entry.cullingListReleaseSlot.Connect(cullingList->OnCullingListRelease, this, &GraphicsComponent::RemoveFromCullingList); entry.listEntry = cullingList->RegisterVolumeTest(this); InvalidateBoundingVolume(); } /*! * \brief Attaches a renderable to the entity * * \param renderable Reference to a renderable element * \param renderOrder Render order of the element */ inline void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, int renderOrder) { return Attach(std::move(renderable), Nz::Matrix4f::Identity(), renderOrder); } /*! * \brief Clears every renderable elements */ inline void GraphicsComponent::Clear() { m_materialEntries.clear(); m_renderables.clear(); if (m_reflectiveMaterialCount > 0) { m_reflectiveMaterialCount = 0; InvalidateReflectionMap(); } InvalidateBoundingVolume(); } /*! * \brief Detaches a renderable to the entity * * \param renderable Reference to a renderable element */ inline void GraphicsComponent::Detach(const Nz::InstancedRenderable* renderable) { for (auto it = m_renderables.begin(); it != m_renderables.end(); ++it) { if (it->renderable == renderable) { InvalidateBoundingVolume(); std::size_t materialCount = renderable->GetMaterialCount(); for (std::size_t i = 0; i < materialCount; ++i) UnregisterMaterial(renderable->GetMaterial(i)); m_renderables.erase(it); break; } } } /*! * \brief Checks if this graphics component requires real-time reflections to be generated * * If any of the materials attached to a GraphicsComponent (via the attached instanced renderable) needs real-time reflections, this function will return true. * * \return True if real-time reflections needs to be generated or false */ inline bool GraphicsComponent::DoesRequireRealTimeReflections() const { return m_reflectiveMaterialCount != 0 && m_reflectionMap; } /*! * \brief Ensures the bounding volume is up to date */ inline void GraphicsComponent::EnsureBoundingVolumeUpdate() const { if (!m_boundingVolumeUpdated) UpdateBoundingVolume(); } /*! * \brief Ensures the transformation matrix is up to date */ inline void GraphicsComponent::EnsureTransformMatrixUpdate() const { if (!m_transformMatrixUpdated) UpdateTransformMatrix(); } /*! * \brief Gets the set of renderable elements * * \param renderables Pointer to the list of renderables * * \remark Produces a NazaraAssert if renderables is invalid */ inline void GraphicsComponent::GetAttachedRenderables(RenderableList* renderables) const { NazaraAssert(renderables, "Invalid renderable list"); renderables->reserve(renderables->size() + m_renderables.size()); for (const Renderable& r : m_renderables) renderables->push_back(r.renderable); } /*! * \brief Gets the number of renderable elements attached to the entity * \return Number of renderable elements */ inline std::size_t GraphicsComponent::GetAttachedRenderableCount() const { return m_renderables.size(); } /*! * \brief Gets the bouding volume of the entity * \return A constant reference to the bounding volume */ inline const Nz::BoundingVolumef& GraphicsComponent::GetBoundingVolume() const { EnsureBoundingVolumeUpdate(); return m_boundingVolume; } inline void GraphicsComponent::RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const { for (auto it = m_volumeCullingEntries.begin(); it != m_volumeCullingEntries.end(); ++it) { if (it->listEntry.GetParent() == cullingList) { if (m_volumeCullingEntries.size() > 1) *it = std::move(m_volumeCullingEntries.back()); m_volumeCullingEntries.pop_back(); break; } } } inline void GraphicsComponent::UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix) { for (auto& renderable : m_renderables) { if (renderable.renderable == instancedRenderable) { renderable.data.localMatrix = localMatrix; InvalidateBoundingVolume(); break; } } } inline void GraphicsComponent::UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder) { for (auto& renderable : m_renderables) { if (renderable.renderable == instancedRenderable) { renderable.data.renderOrder = renderOrder; break; } } } /*! * \brief Invalidates the bounding volume */ inline void GraphicsComponent::InvalidateBoundingVolume() const { m_boundingVolumeUpdated = false; } /*! * \brief Invalidates every renderable elements */ inline void GraphicsComponent::InvalidateRenderables() { for (Renderable& r : m_renderables) r.dataUpdated = false; } /*! * \brief Invalidates the transformation matrix */ inline void GraphicsComponent::InvalidateTransformMatrix() { m_transformMatrixUpdated = false; InvalidateBoundingVolume(); InvalidateRenderables(); } }