diff --git a/src/editor/src/gui/core.cpp b/src/editor/src/gui/core.cpp index b6cd97b..87d1bf5 100644 --- a/src/editor/src/gui/core.cpp +++ b/src/editor/src/gui/core.cpp @@ -17,6 +17,7 @@ #include "FileBrowser.hpp" #include "engine/assets/model/Model.hpp" #include "engine/debug/DEBUG_NAMES.hpp" +#include "engine/debug/drawers.hpp" #include "engine/debug/profiling/counters.hpp" #include "engine/debug/timing/FlameGraph.hpp" #include "engine/descriptors/DescriptorPool.hpp" @@ -193,11 +194,60 @@ namespace fgl::engine::gui static GameObject* selected_object { nullptr }; + void itterateGameObjectNode( FrameInfo& info, const OctTreeNode& node ) + { + if ( node.isLeaf() ) + { + if ( node.itemCount() == 0 ) return; + + const auto& objects { node.getLeaf() }; + for ( const GameObject& object : objects ) + { + ImGui::PushID( object.getId() ); + + debug::drawLine( object.getPosition(), node.getFitCenter() ); + + if ( ImGui::TreeNodeEx( object.getName().c_str(), ImGuiTreeNodeFlags_Leaf ) ) + { + ImGui::TreePop(); + } + ImGui::PopID(); + } + } + else if ( node.isBranch() ) + { + const auto& branches { node.getBranches() }; + + for ( std::size_t x = 0; x < 2; ++x ) + { + for ( std::size_t y = 0; y < 2; ++y ) + { + for ( std::size_t z = 0; z < 2; ++z ) + { + const auto item_count { branches[ x ][ y ][ z ]->itemCount() }; + const auto str { std::format( "{}x{}x{}: {}", x, y, z, item_count ) }; + + if ( ImGui::TreeNodeEx( + str.c_str(), + ImGuiTreeNodeFlags_DefaultOpen | ( item_count == 0 ? ImGuiTreeNodeFlags_Leaf : 0 ) ) ) + { + itterateGameObjectNode( info, *( branches[ x ][ y ][ z ] ) ); + ImGui::TreePop(); + } + } + } + } + } + } + void drawEntityGUI( FrameInfo& info ) { ZoneScoped; ImGui::Begin( OBJECT_TREE_VIEW_NAME ); + itterateGameObjectNode( info, info.game_objects ); + + /* for ( OctTreeNodeLeaf* leaf : info.game_objects.getAllLeafs() ) { for ( GameObject& entity : *leaf ) @@ -212,6 +262,7 @@ namespace fgl::engine::gui ImGui::PopID(); } } + */ ImGui::End(); } diff --git a/src/engine/math/intersections.hpp b/src/engine/math/intersections.hpp index fe8cd8e..c638c31 100644 --- a/src/engine/math/intersections.hpp +++ b/src/engine/math/intersections.hpp @@ -2,6 +2,8 @@ // Created by kj16609 on 10/28/24. // +#include "intersections/aabb/intersections.hpp" +#include "intersections/aabc/intersections.hpp" #include "intersections/frustum/intersections.hpp" #include "intersections/line/intersections.hpp" diff --git a/src/engine/math/intersections/aabb/coordinate.cpp b/src/engine/math/intersections/aabb/coordinate.cpp new file mode 100644 index 0000000..cbacfb6 --- /dev/null +++ b/src/engine/math/intersections/aabb/coordinate.cpp @@ -0,0 +1,27 @@ +// +// Created by kj16609 on 10/31/24. +// + +#include "engine/primitives/points/Coordinate.hpp" + +#include "engine/primitives/boxes/AxisAlignedBoundingBox.hpp" + +namespace fgl::engine::intersections +{ + + template < CS CType > + bool contains( const AxisAlignedBoundingBox< CType >& aabb, const Coordinate< CType >& point ) + { + const Coordinate< CType > centered_coordinate { point - aabb.getPosition() }; + + const bool top_in_range { glm::all( glm::lessThanEqual( centered_coordinate.vec(), aabb.scale() ) ) }; + const bool bottom_in_range { glm::all( glm::greaterThanEqual( centered_coordinate.vec(), -aabb.scale() ) ) }; + + return top_in_range && bottom_in_range; + } + + + + template bool contains< CS::World >( const AxisAlignedBoundingBox< CS::World >&, const Coordinate< CS::World >& ); + +} // namespace fgl::engine::intersections diff --git a/src/engine/math/intersections/aabb/intersections.hpp b/src/engine/math/intersections/aabb/intersections.hpp new file mode 100644 index 0000000..8ea4236 --- /dev/null +++ b/src/engine/math/intersections/aabb/intersections.hpp @@ -0,0 +1,13 @@ +// +// Created by kj16609 on 10/31/24. +// + +#include "engine/primitives/boxes/AxisAlignedBoundingBox.hpp" + +namespace fgl::engine::intersections +{ + + template < CS CType > + bool contains( const AxisAlignedBoundingBox< CType >& aabb, const Coordinate< CType >& point ); + +} // namespace fgl::engine::intersections diff --git a/src/engine/math/intersections/aabc/coordinate.cpp b/src/engine/math/intersections/aabc/coordinate.cpp new file mode 100644 index 0000000..75e9944 --- /dev/null +++ b/src/engine/math/intersections/aabc/coordinate.cpp @@ -0,0 +1,25 @@ +// +// Created by kj16609 on 10/31/24. +// + +#include "engine/primitives/points/Coordinate.hpp" + +#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp" + +namespace fgl::engine::intersections +{ + + template < CS CType > + bool contains( const AxisAlignedBoundingCube< CType >& aabc, const Coordinate< CType >& point ) + { + const Coordinate< CType > centered_coordinate { point - aabc.getPosition() }; + + const bool top_in_range { glm::all( glm::lessThanEqual( centered_coordinate.vec(), aabc.scale() ) ) }; + const bool bottom_in_range { glm::all( glm::greaterThanEqual( centered_coordinate.vec(), -aabc.scale() ) ) }; + + return top_in_range && bottom_in_range; + } + + template bool contains< CS::World >( const AxisAlignedBoundingCube< CS::World >&, const Coordinate< CS::World >& ); + +} // namespace fgl::engine::intersections diff --git a/src/engine/math/intersections/aabc/intersections.hpp b/src/engine/math/intersections/aabc/intersections.hpp new file mode 100644 index 0000000..c59bf93 --- /dev/null +++ b/src/engine/math/intersections/aabc/intersections.hpp @@ -0,0 +1,13 @@ +// +// Created by kj16609 on 10/31/24. +// + +#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp" + +namespace fgl::engine::intersections +{ + + template < CS CType > + bool contains( const AxisAlignedBoundingCube< CType >& aabb, const Coordinate< CType >& point ); + +} // namespace fgl::engine::intersections diff --git a/src/engine/math/intersections/obb/coordinate.cpp b/src/engine/math/intersections/obb/coordinate.cpp new file mode 100644 index 0000000..97bfade --- /dev/null +++ b/src/engine/math/intersections/obb/coordinate.cpp @@ -0,0 +1,20 @@ +// +// Created by kj16609 on 10/31/24. +// + +#include "engine/primitives/points/Coordinate.hpp" + +#include "engine/primitives/boxes/OrientedBoundingBox.hpp" + +namespace fgl::engine::intersections +{ + + template < CS CType > + bool contains( const OrientedBoundingBox< CType >& obb, const Coordinate< CType >& point ) + { + FGL_UNIMPLEMENTED(); + } + + template bool contains< CS::World >( const OrientedBoundingBox< CS::World >&, const Coordinate< CS::World >& ); + +} // namespace fgl::engine::intersections diff --git a/src/engine/math/intersections/obb/intersections.hpp b/src/engine/math/intersections/obb/intersections.hpp new file mode 100644 index 0000000..ba1e693 --- /dev/null +++ b/src/engine/math/intersections/obb/intersections.hpp @@ -0,0 +1,13 @@ +// +// Created by kj16609 on 10/31/24. +// + +#include "engine/primitives/boxes/OrientedBoundingBox.hpp" + +namespace fgl::engine::intersections +{ + + template < CS CType > + bool contains( const OrientedBoundingBox< CType >& aabb, const Coordinate< CType >& point ); + +} // namespace fgl::engine::intersections diff --git a/src/engine/primitives/boxes/AxisAlignedBoundingBox.hpp b/src/engine/primitives/boxes/AxisAlignedBoundingBox.hpp index 6825c7b..1c3a2ca 100644 --- a/src/engine/primitives/boxes/AxisAlignedBoundingBox.hpp +++ b/src/engine/primitives/boxes/AxisAlignedBoundingBox.hpp @@ -25,7 +25,7 @@ namespace fgl::engine constexpr static auto SpaceType { CType }; - explicit AxisAlignedBoundingBox( + AxisAlignedBoundingBox( const Coordinate< CType > top_right_forward, const Coordinate< CType > bottom_left_back ) : m_top_right_forward( top_right_forward ), m_bottom_left_back( bottom_left_back ) @@ -35,7 +35,7 @@ namespace fgl::engine assert( m_top_right_forward.z > m_bottom_left_back.z ); } - explicit AxisAlignedBoundingBox( const Coordinate< CType > midpoint, const Scale scale ) : + AxisAlignedBoundingBox( const Coordinate< CType > midpoint, const Scale scale ) : AxisAlignedBoundingBox( midpoint + scale, midpoint - scale ) { assert( m_top_right_forward.x > m_bottom_left_back.x ); @@ -43,6 +43,7 @@ namespace fgl::engine assert( m_top_right_forward.z > m_bottom_left_back.z ); } + //TODO: This should be removed from access in favor of OBB::alignToWorld() explicit AxisAlignedBoundingBox( const OrientedBoundingBox< CType >& oobb ); AxisAlignedBoundingBox& combine( const AxisAlignedBoundingBox& other ); diff --git a/src/engine/primitives/boxes/OrientedBoundingBox.cpp b/src/engine/primitives/boxes/OrientedBoundingBox.cpp index 6a8af18..572bb63 100644 --- a/src/engine/primitives/boxes/OrientedBoundingBox.cpp +++ b/src/engine/primitives/boxes/OrientedBoundingBox.cpp @@ -225,6 +225,12 @@ namespace fgl::engine return AxisAlignedBoundingBox< CType >( Coordinate< CType >( max ), Coordinate< CType >( min ) ); } + template < CoordinateSpace CType > + Coordinate< CType > OrientedBoundingBox< CType >::getPosition() const + { + return m_transform.translation; + } + template < CoordinateSpace CType > std::array< LineSegment< CType >, interface::BoundingBox::LINE_COUNT > OrientedBoundingBox< CType >::lines() const { diff --git a/src/engine/primitives/boxes/OrientedBoundingBox.hpp b/src/engine/primitives/boxes/OrientedBoundingBox.hpp index 2a36473..286ee28 100644 --- a/src/engine/primitives/boxes/OrientedBoundingBox.hpp +++ b/src/engine/primitives/boxes/OrientedBoundingBox.hpp @@ -111,6 +111,8 @@ namespace fgl::engine OrientedBoundingBox combine( const OrientedBoundingBox& other ) const; AxisAlignedBoundingBox< CType > alignToWorld() const; + + Coordinate< CType > getPosition() const; }; template < CoordinateSpace CType, MatrixType MType > diff --git a/src/engine/tree/octtree/OctTreeNode.cpp b/src/engine/tree/octtree/OctTreeNode.cpp index 85267de..1c2aaf4 100644 --- a/src/engine/tree/octtree/OctTreeNode.cpp +++ b/src/engine/tree/octtree/OctTreeNode.cpp @@ -241,6 +241,9 @@ namespace fgl::engine } objects.emplace_back( std::move( obj ) ); + + recalculateBounds(); + return this; } else if ( std::holds_alternative< OctTreeNodeArray >( m_node_data ) ) @@ -252,25 +255,59 @@ namespace fgl::engine FGL_UNREACHABLE(); } + bool OctTreeNode::isLeaf() const + { + return std::holds_alternative< OctTreeNodeLeaf >( m_node_data ); + } + + bool OctTreeNode::isBranch() const + { + return std::holds_alternative< OctTreeNodeArray >( m_node_data ); + } + + std::size_t OctTreeNode::itemCount() const + { + //TODO: Store this value in the nodes itself + if ( !isLeaf() ) + { + std::size_t sum { 0 }; + + for ( std::size_t x = 0; x < 2; ++x ) + { + for ( std::size_t y = 0; y < 2; ++y ) + { + for ( std::size_t z = 0; z < 2; ++z ) + { + sum += std::get< OctTreeNodeArray >( m_node_data )[ x ][ y ][ z ]->itemCount(); + } + } + } + + return sum; + } + + return std::get< OctTreeNodeLeaf >( m_node_data ).size(); + } + + const OctTreeNodeArray& OctTreeNode::getBranches() const + { + return std::get< OctTreeNodeArray >( m_node_data ); + } + + const OctTreeNodeLeaf& OctTreeNode::getLeaf() const + { + return std::get< OctTreeNodeLeaf >( m_node_data ); + } + bool OctTreeNode::isInFrustum( const Frustum& frustum ) const { #if ENABLE_IMGUI if ( !isEmpty() && intersects( frustum, m_fit_bounding_box ) ) { - if ( ( draw_inview_bounds || ( std::holds_alternative< OctTreeNodeLeaf >( this->m_node_data ) ) - || draw_branches ) - && m_parent ) [[unlikely]] + if ( isLeaf() && itemCount() > 0 ) [[unlikely]] { if ( draw_leaf_fit_bounds ) [[unlikely]] debug::drawBoundingBox( m_fit_bounding_box ); - /* - debug::drawBoundingBox( - m_fit_bounding_box, - glm::vec3( - m_fit_bounding_box.getPosition().x > 0.0f ? 1.0f : 0.0f, - m_fit_bounding_box.getPosition().y > 0.0f ? 1.0f : 0.0f, - m_fit_bounding_box.getPosition().z > 0.0f ? 1.0f : 0.0f ) ); - */ if ( draw_leaf_real_bounds ) [[unlikely]] debug::drawBoundingBox( m_bounds ); } @@ -285,47 +322,42 @@ namespace fgl::engine #endif } + bool OctTreeNode::isEmpty() const + { + return std::holds_alternative< OctTreeNodeLeaf >( m_node_data ) + && std::get< OctTreeNodeLeaf >( m_node_data ).empty(); + } + + /** + * + * @return Returns true if the fit bounding box is larger then the virtual bounds + */ void OctTreeNode::recalculateBounds() { - m_fit_bounding_box = m_bounds; + if ( isLeaf() ) + return recalculateLeafBounds(); + else if ( isBranch() ) + return recalculateNodeBounds(); - if ( std::holds_alternative< NodeDataT >( m_node_data ) ) - { - // We aren't a leaf. So we need to use the bounding box of the children below us + FGL_UNREACHABLE(); + } - const auto& nodes { std::get< NodeDataT >( m_node_data ) }; + std::vector< OctTreeNodeLeaf* > OctTreeNode::getAllLeafs() + { + ZoneScoped; + std::vector< OctTreeNodeLeaf* > leafs {}; + leafs.reserve( LEAF_RESERVE_SIZE ); + this->getAllLeafs( leafs ); + return leafs; + } - for ( std::size_t x = 0; x < 2; ++x ) - { - for ( std::size_t y = 0; y < 2; ++y ) - { - for ( std::size_t z = 0; z < 2; ++z ) - { - nodes[ x ][ y ][ z ]->recalculateBounds(); - m_fit_bounding_box = m_fit_bounding_box.combine( nodes[ x ][ y ][ z ]->m_fit_bounding_box ); - } - } - } - } - else if ( std::holds_alternative< LeafDataT >( m_node_data ) ) - { - const auto& data { std::get< LeafDataT >( m_node_data ) }; - - for ( const auto& game_object : data ) - { - auto model_components { game_object.getComponents< ModelComponent >() }; - - for ( const auto& model : model_components ) - { - const OrientedBoundingBox model_bounding_box { ( *model )->getBoundingBox() }; - - const OrientedBoundingBox< CoordinateSpace::World > world_bounding_box { model->m_transform.mat() - * model_bounding_box }; - - m_fit_bounding_box = m_fit_bounding_box.combine( world_bounding_box.alignToWorld() ); - } - } - } + std::vector< OctTreeNodeLeaf* > OctTreeNode::getAllLeafsInFrustum( const Frustum& frustum ) + { + ZoneScoped; + std::vector< OctTreeNodeLeaf* > leafs {}; + leafs.reserve( LEAF_RESERVE_SIZE ); + this->getAllLeafsInFrustum( frustum, leafs ); + return leafs; } void OctTreeNode::clear() @@ -338,12 +370,26 @@ namespace fgl::engine { const auto& node_array { std::get< OctTreeNodeArray >( this->m_node_data ) }; - for ( std::size_t x = 0; x < 2; ++x ) - for ( std::size_t y = 0; y < 2; ++y ) - for ( std::size_t z = 0; z < 2; ++z ) node_array[ x ][ y ][ z ]->clear(); + FOR_EACH_OCTTREE_NODE + { + node_array[ x ][ y ][ z ]->clear(); + } } } + WorldCoordinate OctTreeNode::getCenter() const + { + return m_bounds.getPosition(); + } + + WorldCoordinate OctTreeNode::getFitCenter() const + { + return m_fit_bounding_box.getPosition(); + } + + void OctTreeNode::drawDebug() const + {} + OctTreeNode* OctTreeNode::findID( const GameObject::GameObjectID id ) { ZoneScoped; @@ -352,33 +398,22 @@ namespace fgl::engine //We are the last node. Check if we have the ID const auto& game_objects { std::get< OctTreeNodeLeaf >( m_node_data ) }; - if ( std::find_if( - game_objects.begin(), - game_objects.end(), - [ id ]( const GameObject& obj ) { return obj.getId() == id; } ) + if ( std::ranges::find_if( game_objects, [ id ]( const GameObject& obj ) { return obj.getId() == id; } ) != game_objects.end() ) { return this; } - else - { - return nullptr; - } + + return nullptr; } else if ( std::holds_alternative< OctTreeNodeArray >( this->m_node_data ) ) { const auto& node_array { std::get< OctTreeNodeArray >( this->m_node_data ) }; - for ( std::size_t x = 0; x < 2; ++x ) + FOR_EACH_OCTTREE_NODE { - for ( std::size_t y = 0; y < 2; ++y ) - { - for ( std::size_t z = 0; z < 2; ++z ) - { - const auto& node { node_array[ x ][ y ][ z ]->findID( id ) }; - if ( node != nullptr ) return node; - } - } + const auto& node { node_array[ x ][ y ][ z ]->findID( id ) }; + if ( node != nullptr ) return node; } return nullptr; @@ -434,105 +469,14 @@ namespace fgl::engine { const auto& nodes { std::get< OctTreeNodeArray >( m_node_data ) }; - for ( std::size_t x = 0; x < 2; ++x ) + FOR_EACH_OCTTREE_NODE { - for ( std::size_t y = 0; y < 2; ++y ) - { - for ( std::size_t z = 0; z < 2; ++z ) - { - auto ret { nodes[ x ][ y ][ z ]->getAllLeafs() }; - out_leafs.insert( out_leafs.end(), ret.begin(), ret.end() ); - } - } + auto ret { nodes[ x ][ y ][ z ]->getAllLeafs() }; + out_leafs.insert( out_leafs.end(), ret.begin(), ret.end() ); } } } - /* - bool OctTreeNode::recalculateBoundingBoxes() - { - ZoneScoped; - const auto old_bounds { m_fit_bounding_box }; - if ( std::holds_alternative< OctTreeNodeArray >( m_node_data ) ) - { - ZoneScopedN( "Process Array" ); - bool bounding_box_changed { false }; - auto& nodes { std::get< OctTreeNodeArray >( m_node_data ) }; - for ( std::size_t x = 0; x < 2; ++x ) - { - for ( std::size_t y = 0; y < 2; ++y ) - { - for ( std::size_t z = 0; z < 2; ++z ) - { - auto& node { nodes[ x ][ y ][ z ] }; - bounding_box_changed |= node->recalculateBoundingBoxes(); - } - } - } - - if ( bounding_box_changed ) - { - //We need to update our bounding box now. - auto new_bounds { nodes[ 0 ][ 0 ][ 0 ]->m_fit_bounding_box }; - - for ( std::size_t x = 0; x < 2; ++x ) - { - for ( std::size_t y = 0; y < 2; ++y ) - { - for ( std::size_t z = 0; z < 2; ++z ) - { - if ( x == 0 && y == 0 && z == 0 ) continue; - auto& node { nodes[ x ][ y ][ z ] }; - new_bounds.combine( node->m_fit_bounding_box ); - } - } - } - - if ( new_bounds == old_bounds ) - { - return false; - } - else - { - this->m_fit_bounding_box = new_bounds; - return true; - } - } - - return false; - } - else if ( std::holds_alternative< OctTreeNodeLeaf >( m_node_data ) ) - { - ZoneScopedN( "Process Leaf" ); - auto& game_objects { std::get< OctTreeNodeLeaf >( m_node_data ) }; - - if ( game_objects.size() == 0 ) return false; - - AxisAlignedBoundingBox< CoordinateSpace::World > new_bounds { game_objects[ 0 ].getPosition() }; - - FGL_ASSUME( game_objects.size() <= MAX_NODES_IN_LEAF ); - - for ( std::size_t i = 1; i < game_objects.size(); ++i ) - { - FGL_ASSUME( i <= MAX_NODES_IN_LEAF )); - new_bounds.combine( game_objects[ i ].getBoundingBox() ); - } - - if ( new_bounds == old_bounds ) - { - return false; - } - else - { - this->m_fit_bounding_box = new_bounds; - return true; - } - } - - FGL_UNREACHABLE(); - } - */ - std::size_t OctTreeNode::reorganize() { std::size_t counter { 0 }; @@ -540,22 +484,17 @@ namespace fgl::engine { const auto& nodes { std::get< NodeDataT >( m_node_data ) }; - for ( std::size_t x = 0; x < 2; ++x ) + FOR_EACH_OCTTREE_NODE { - for ( std::size_t y = 0; y < 2; ++y ) - { - for ( std::size_t z = 0; z < 2; ++z ) - { - if ( x == 0 && y == 0 && z == 0 ) continue; - const auto& node { nodes[ x ][ y ][ z ] }; - counter += node->reorganize(); - } - } + // Why did I skip the 0,0,0 node previously? + // if ( x == 0 && y == 0 && z == 0 ) continue; + const auto& node { nodes[ x ][ y ][ z ] }; + counter += node->reorganize(); } return counter; } - if ( std::holds_alternative< LeafDataT >( m_node_data ) ) + else if ( std::holds_alternative< LeafDataT >( m_node_data ) ) { //Check if any of the nodes in this group need to be moved. @@ -578,4 +517,85 @@ namespace fgl::engine FGL_UNREACHABLE(); } + bool OctTreeNode::isBoundsExpanded() + { + return m_fit_bounding_box == m_bounds; + /* + const auto fit_points { m_fit_bounding_box.points() }; + for ( const auto& p : fit_points ) + { + // Return true if a point is outside of the bounds. This indicates that out bounding box is bigger then our bounds. + if ( !m_bounds.contains( p ) ) return true; + } + + return false; + */ + } + + void OctTreeNode::recalculateNodeBounds() + { + FGL_ASSERT( std::holds_alternative< NodeDataT >( m_node_data ), "Node data was not an array!" ); + const auto& nodes { std::get< NodeDataT >( m_node_data ) }; + + // We start out by telling all of our children to recalculate their bounds + m_fit_bounding_box = static_cast< AxisAlignedBoundingBox< CoordinateSpace::World > >( m_bounds ); + + FOR_EACH_OCTTREE_NODE + { + // If true then the bounds were bigger then the inital bounding box. So we should try to combine it with out current bounding box. + m_fit_bounding_box = m_fit_bounding_box.combine( nodes[ x ][ y ][ z ]->m_fit_bounding_box ); + } + + // if ( isBoundsExpanded() && m_parent ) + if ( m_parent ) m_parent->recalculateBounds(); + } + + void OctTreeNode::recalculateLeafBounds() + { + FGL_ASSERT( std::holds_alternative< LeafDataT >( m_node_data ), "Node data was not a leaf!" ); + const auto& data { std::get< LeafDataT >( m_node_data ) }; + + if ( data.empty() ) + { + m_fit_bounding_box = static_cast< AxisAlignedBoundingBox< CoordinateSpace::World > >( m_bounds ); + return; + } + + // If true, Then the fit has already been set and we should combine with it + bool fit_set { false }; + + for ( const auto& game_object : data ) + { + auto model_components { game_object.getComponents< ModelComponent >() }; + const Matrix< MatrixType::ModelToWorld > game_object_transform { game_object.getTransform().mat() }; + + for ( const auto& model : model_components ) + { + const OrientedBoundingBox< CS::Model > model_bounding_box { ( *model )->getBoundingBox() }; + + const Matrix< MatrixType::ModelToWorld > model_transform { model->m_transform.mat() }; + + // Combine the game object and model transform + const Matrix< MatrixType::ModelToWorld > combined_transform { model_transform * game_object_transform }; + + const OrientedBoundingBox< CoordinateSpace::World > world_bounding_box { combined_transform + * model_bounding_box }; + + const auto aligned_bounding_box { world_bounding_box.alignToWorld() }; + + if ( fit_set ) + m_fit_bounding_box = m_fit_bounding_box.combine( aligned_bounding_box ); + else + { + m_fit_bounding_box = aligned_bounding_box; + fit_set = true; + } + } + } + + // Have our parent recalculate it's bounds + // if ( isBoundsExpanded() && m_parent ) + if ( m_parent ) m_parent->recalculateBounds(); + } + } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/tree/octtree/OctTreeNode.hpp b/src/engine/tree/octtree/OctTreeNode.hpp index cd757ea..95b1165 100644 --- a/src/engine/tree/octtree/OctTreeNode.hpp +++ b/src/engine/tree/octtree/OctTreeNode.hpp @@ -4,8 +4,6 @@ #pragma once -#include - #include "engine/gameobjects/GameObject.hpp" #include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp" @@ -65,6 +63,9 @@ namespace fgl::engine OctTreeNode& operator=( const OctTreeNode& ) = delete; OctTreeNode& operator=( OctTreeNode&& ) = delete; void clear(); + WorldCoordinate getCenter() const; + WorldCoordinate getFitCenter() const; + void drawDebug() const; private: @@ -89,11 +90,7 @@ namespace fgl::engine bool isInFrustum( const Frustum& frustum ) const; - bool isEmpty() const - { - return std::holds_alternative< OctTreeNodeLeaf >( m_node_data ) - && std::get< OctTreeNodeLeaf >( m_node_data ).empty(); - } + bool isEmpty() const; auto getGameObjectItter( GameObject::GameObjectID id ); @@ -109,30 +106,34 @@ namespace fgl::engine //! Rebuilds the tree checking if nodes have moved. std::size_t reorganize(); + //! Returns true if the fixed bounding box is larger then the inital bounding box + bool isBoundsExpanded(); + + void recalculateNodeBounds(); + + void recalculateLeafBounds(); + void recalculateBounds(); constexpr static std::size_t LEAF_RESERVE_SIZE { 1024 }; - [[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafs() - { - ZoneScoped; - std::vector< OctTreeNodeLeaf* > leafs {}; - leafs.reserve( LEAF_RESERVE_SIZE ); - this->getAllLeafs( leafs ); - return leafs; - } + [[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafs(); - [[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafsInFrustum( const Frustum& frustum ) - { - ZoneScoped; - std::vector< OctTreeNodeLeaf* > leafs {}; - leafs.reserve( LEAF_RESERVE_SIZE ); - this->getAllLeafsInFrustum( frustum, leafs ); - return leafs; - } + [[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafsInFrustum( const Frustum& frustum ); //! Adds a game object, Will split the node if the auto split threshold is reached OctTreeNode* addGameObject( GameObject&& obj ); + bool isLeaf() const; + bool isBranch() const; + + std::size_t itemCount() const; + const OctTreeNodeArray& getBranches() const; + const OctTreeNodeLeaf& getLeaf() const; }; +#define FOR_EACH_OCTTREE_NODE \ + for ( std::size_t x = 0; x < 2; ++x ) \ + for ( std::size_t y = 0; y < 2; ++y ) \ + for ( std::size_t z = 0; z < 2; ++z ) + } // namespace fgl::engine \ No newline at end of file