Cleanup octree and get started on chunk system

This commit is contained in:
2024-11-03 12:27:43 -05:00
parent 6439b1cbf2
commit 46464fa6d2
16 changed files with 284 additions and 90 deletions

View File

@@ -194,21 +194,23 @@ namespace fgl::engine::gui
static GameObject* selected_object { nullptr };
void itterateGameObjectNode( FrameInfo& info, const OctTreeNode& node )
void itterateGameObjectNode( FrameInfo& info, OctTreeNode& node )
{
if ( node.isLeaf() )
{
if ( node.itemCount() == 0 ) return;
const auto& objects { node.getLeaf() };
for ( const GameObject& object : objects )
auto& objects { node.getLeaf() };
for ( GameObject& object : objects )
{
ImGui::PushID( object.getId() );
debug::drawLine( object.getPosition(), node.getFitCenter() );
if ( ImGui::TreeNodeEx( object.getName().c_str(), ImGuiTreeNodeFlags_Leaf ) )
{
if ( ImGui::IsItemClicked() )
{
selected_object = &object;
}
ImGui::TreePop();
}
ImGui::PopID();

View File

@@ -51,7 +51,7 @@ namespace fgl::engine::gui
Model::createModel( data->path, info.model_vertex_buffer, info.model_index_buffer )
};
obj.addFlag( IS_ENTITY | IS_VISIBLE );
obj.addFlag( IsEntity | IsVisible );
auto component {
std::make_unique< ModelComponent >( std::move( model ) )

View File

@@ -58,8 +58,8 @@ namespace fgl::engine
initMaterialDataVec( m_material_data_pool );
constexpr auto offset { 2.0f };
constexpr std::size_t grid_size { 16 };
constexpr auto offset { 8.0f };
constexpr std::size_t grid_size { 6 };
constexpr float factor_offset { 1.0f / static_cast< float >( grid_size ) };
for ( std::size_t x = 0; x < grid_size; ++x )
@@ -92,7 +92,7 @@ namespace fgl::engine
}
}
obj.getTransform().translation = WorldCoordinate( x * offset, y * offset, 0.0f );
obj.getTransform().translation = WorldCoordinate( 10.0 + x * offset, 10.0 + y * offset, 0.0f );
m_game_objects_root.addGameObject( std::move( obj ) );
}

View File

@@ -53,9 +53,11 @@
#define FGL_STRICT_ALIGNMENT( bytesize ) [[gnu::warn_if_not_aligned( bytesize )]]
#ifndef NDEBUG
#include <format>
#include <stdexcept>
#define FGL_ASSERT( test, msg ) assert( ( test ) && "msg" );
//if ( !( test ) ) throw std::runtime_error( msg );
#define FGL_ASSERT( test, msg ) \
if ( !( test ) ) \
throw std::runtime_error( std::format( "{}:{}:{}: {}", __FILE__, __LINE__, __PRETTY_FUNCTION__, msg ) );
#else
#define FGL_ASSERT( test, msg )
#endif
@@ -69,4 +71,10 @@
std::unreachable()
#else
#define FGL_UNREACHABLE() std::unreachable()
#endif
#endif
#define FGL_NOTNAN( value ) FGL_ASSERT( !std::isnan( value ), "Value is NaN!" )
#define FGL_NOTNANVEC3( vec3 ) \
FGL_ASSERT( !std::isnan( ( vec3 ).x ), "X value was NaN!" ); \
FGL_ASSERT( !std::isnan( ( vec3 ).y ), "Y value was NaN!" ); \
FGL_ASSERT( !std::isnan( ( vec3 ).z ), "Z value was NaN!" )

View File

@@ -604,7 +604,7 @@ namespace fgl::engine
std::unique_ptr< ModelComponent > component { std::make_unique< ModelComponent >( std::move( model ) ) };
obj.addComponent( std::move( component ) );
obj.addFlag( IS_VISIBLE | IS_ENTITY );
obj.addFlag( IsVisible | IsEntity );
const auto transform { loadTransform( node_idx, root ) };

View File

@@ -15,7 +15,7 @@
namespace fgl::engine::constants
{
constexpr glm::vec3 DEFAULT_VEC3 { std::numeric_limits< float >::max() };
constexpr glm::vec3 DEFAULT_VEC3 { std::numeric_limits< float >::signaling_NaN() };
constexpr glm::vec3 WORLD_CENTER { 0.0f, 0.0f, 0.0f };

View File

@@ -25,11 +25,11 @@ namespace fgl::engine
enum GameObjectFlagMask : GameObjectFlagType
{
NONE_FLAG = 0,
IS_STATIC = 1 << 0, //! Object can not move
IS_VISIBLE = 1 << 1, //! Only return visible objects
IS_ENTITY = 1 << 2,
MASK_DEFAULT = IS_VISIBLE,
NoneFlag = 0,
IsStatic = 1 << 0, //! Object can not move
IsVisible = 1 << 1, //! Only return visible objects
IsEntity = 1 << 2,
MaskDefault = IsVisible,
};
class GameObject
@@ -44,7 +44,7 @@ namespace fgl::engine
private:
GameObjectID m_id { INVALID_ID };
GameObjectFlagType object_flags { GameObjectFlagMask::MASK_DEFAULT };
GameObjectFlagType object_flags { GameObjectFlagMask::MaskDefault };
GameObjectTransform m_transform {};
std::vector< GameObjectComponentPtr > components {};

View File

@@ -93,6 +93,11 @@ namespace fgl::engine
template < CoordinateSpace CType >
AxisAlignedBoundingBox< CType >& AxisAlignedBoundingBox< CType >::combine( const AxisAlignedBoundingBox& other )
{
FGL_NOTNANVEC3( other.m_top_right_forward );
FGL_NOTNANVEC3( other.m_bottom_left_back );
FGL_NOTNANVEC3( this->m_top_right_forward );
FGL_NOTNANVEC3( this->m_bottom_left_back );
const Coordinate< CType > new_top_right_forward {
std::max( this->m_top_right_forward.x, other.m_top_right_forward.x ),
std::max( this->m_top_right_forward.y, other.m_top_right_forward.y ),
@@ -118,6 +123,11 @@ namespace fgl::engine
const auto other_trf { other.topRightForward() };
const auto other_blb { other.bottomLeftBack() };
FGL_NOTNANVEC3( other.topRightForward() );
FGL_NOTNANVEC3( other.bottomLeftBack() );
FGL_NOTNANVEC3( this->m_top_right_forward );
FGL_NOTNANVEC3( this->m_bottom_left_back );
const Coordinate< CType > new_top_right_forward {
std::max( this->m_top_right_forward.x, other_trf.x ),
std::max( this->m_top_right_forward.y, other_trf.y ),
@@ -141,17 +151,16 @@ namespace fgl::engine
m_top_right_forward( constants::DEFAULT_VEC3 ),
m_bottom_left_back( -constants::DEFAULT_VEC3 )
{
FGL_NOTNANVEC3( oobb.topRightForward() );
FGL_NOTNANVEC3( oobb.bottomLeftBack() );
FGL_NOTNANVEC3( this->m_top_right_forward );
FGL_NOTNANVEC3( this->m_bottom_left_back );
if ( oobb.m_transform.rotation
== Rotation() ) // If default rotation then we can simply just take it as the box is
{
assert( oobb.topRightForward().vec() != constants::DEFAULT_VEC3 );
assert( oobb.bottomLeftBack().vec() != -constants::DEFAULT_VEC3 );
m_top_right_forward = oobb.topRightForward();
m_bottom_left_back = oobb.bottomLeftBack();
assert( m_top_right_forward.vec() != constants::DEFAULT_VEC3 );
assert( m_bottom_left_back.vec() != -constants::DEFAULT_VEC3 );
}
else
{
@@ -166,28 +175,9 @@ namespace fgl::engine
m_bottom_left_back.y = std::min( m_bottom_left_back.y, point.y );
m_bottom_left_back.z = std::min( m_bottom_left_back.z, point.z );
}
assert( m_top_right_forward.vec() != constants::DEFAULT_VEC3 );
assert( m_bottom_left_back.vec() != -constants::DEFAULT_VEC3 );
}
}
/*
template < CoordinateSpace CType >
AxisAlignedBoundingBox< CType >& AxisAlignedBoundingBox< CType >::combine( const OrientedBoundingBox< CType >&
other )
{
const AxisAlignedBoundingBox< CType > aabb { other };
if ( this->m_top_right_forward == Coordinate< CType >( constants::DEFAULT_VEC3 )
|| this->m_bottom_left_back == Coordinate< CType >( constants::DEFAULT_VEC3 ) )
return *this = aabb;
else
{
return this->combine( aabb );
}
}
*/
template class AxisAlignedBoundingBox< CoordinateSpace::Model >;
template class AxisAlignedBoundingBox< CoordinateSpace::World >;
} // namespace fgl::engine

View File

@@ -5,6 +5,7 @@
#pragma once
#include "BoundingBox.hpp"
#include "engine/FGL_DEFINES.hpp"
#include "engine/primitives/Scale.hpp"
#include "engine/primitives/points/Coordinate.hpp"
#include "engine/primitives/vectors/NormalVector.hpp"
@@ -33,6 +34,13 @@ namespace fgl::engine
assert( m_top_right_forward.x > m_bottom_left_back.x );
assert( m_top_right_forward.y > m_bottom_left_back.y );
assert( m_top_right_forward.z > m_bottom_left_back.z );
FGL_NOTNAN( m_bottom_left_back.x );
FGL_NOTNAN( m_bottom_left_back.y );
FGL_NOTNAN( m_bottom_left_back.z );
FGL_NOTNAN( m_bottom_left_back.x );
FGL_NOTNAN( m_bottom_left_back.y );
FGL_NOTNAN( m_bottom_left_back.z );
}
AxisAlignedBoundingBox( const Coordinate< CType > midpoint, const Scale scale ) :
@@ -41,6 +49,13 @@ namespace fgl::engine
assert( m_top_right_forward.x > m_bottom_left_back.x );
assert( m_top_right_forward.y > m_bottom_left_back.y );
assert( m_top_right_forward.z > m_bottom_left_back.z );
FGL_NOTNAN( m_bottom_left_back.x );
FGL_NOTNAN( m_bottom_left_back.y );
FGL_NOTNAN( m_bottom_left_back.z );
FGL_NOTNAN( m_bottom_left_back.x );
FGL_NOTNAN( m_bottom_left_back.y );
FGL_NOTNAN( m_bottom_left_back.z );
}
//TODO: This should be removed from access in favor of OBB::alignToWorld()

View File

@@ -208,8 +208,10 @@ namespace fgl::engine
AxisAlignedBoundingBox< CType > OrientedBoundingBox< CType >::alignToWorld() const
{
const auto points { this->points() };
glm::vec3 max { std::numeric_limits< glm::vec3::type >::infinity() };
glm::vec3 min { -std::numeric_limits< glm::vec3::type >::infinity() };
static_assert( std::same_as< glm::vec3::value_type, float > );
constexpr glm::vec3::value_type INF { std::numeric_limits< glm::vec3::value_type >::infinity() };
glm::vec3 max { -INF };
glm::vec3 min { INF };
for ( const auto& point : points )
{
@@ -222,6 +224,9 @@ namespace fgl::engine
min.z = glm::min( min.z, point.z );
}
FGL_ASSERT( glm::all( glm::notEqual( max, glm::vec3( -INF ) ) ), "Max was still infinity" );
FGL_ASSERT( glm::all( glm::notEqual( min, glm::vec3( INF ) ) ), "Min was still infinity" );
return AxisAlignedBoundingBox< CType >( Coordinate< CType >( max ), Coordinate< CType >( min ) );
}

View File

@@ -46,7 +46,7 @@ namespace fgl::engine
explicit Matrix( const glm::mat4& matrix ) : glm::mat4( matrix ) {}
Matrix operator*( const Matrix& other )
Matrix operator*( const Matrix& other ) const
{
return Matrix( static_cast< glm::mat4 >( *this ) * static_cast< glm::mat4 >( other ) );
}

View File

@@ -155,7 +155,7 @@ namespace fgl::engine
TracyVkZone( info.tracy_ctx, *command_buffer, "Render textured entities" );
auto [ draw_commands, model_matricies ] =
getDrawCallsFromTree( info.game_objects, info.camera->getFrustumBounds(), IS_VISIBLE | IS_ENTITY );
getDrawCallsFromTree( info.game_objects, info.camera->getFrustumBounds(), IsVisible | IsEntity );
if ( draw_commands.empty() ) return;

47
src/engine/tree/Chunk.cpp Normal file
View File

@@ -0,0 +1,47 @@
//
// Created by kj16609 on 11/3/24.
//
#include "Chunk.hpp"
#include "engine/utils.hpp"
namespace fgl::engine::tree
{
std::shared_ptr< Chunk > ChunkManager::createChunk( const ChunkID id )
{
std::shared_ptr< Chunk > chunk { std::make_shared< Chunk >( id ) };
m_chunks.insert( std::make_pair( id, chunk ) );
return chunk;
}
std::shared_ptr< Chunk > ChunkManager::getChunk( const ChunkID id )
{}
ChunkID getID( const glm::vec3 point )
{
// the inital chunk starts at 0,0,0. meaning that the bounds of the inital chunk goes from
// +/- CHUNK_SIZE / 2.0f
// We need to start by dividing the point into the size of the chunks.
constexpr glm::vec3 CHUNK_VEC3 { Chunk::CHUNK_HALF };
const glm::vec3 chunk_pos { point / CHUNK_VEC3 };
// chunk_pos now needs to be clamped to interegers, we always round DOWN.
const glm::vec3 round_offset { glm::sign( chunk_pos ) * glm::vec3( 0.5f ) };
const glm::vec3 chunk_coords { glm::round( chunk_pos + round_offset ) };
const glm::vec< 3, int > chunk_coords_i { chunk_coords };
ChunkID hash { 0 };
engine::hashCombine( hash, chunk_coords_i[ 0 ], chunk_coords_i[ 1 ], chunk_coords_i[ 2 ] );
return hash;
}
Chunk::Chunk( const ChunkID id ) : m_id( id ), m_center( getPosition( id ) )
{}
} // namespace fgl::engine::tree

70
src/engine/tree/Chunk.hpp Normal file
View File

@@ -0,0 +1,70 @@
//
// Created by kj16609 on 11/2/24.
//
#pragma once
#include <memory>
#include <queue>
#include <unordered_map>
#include "engine/gameobjects/GameObject.hpp"
#include "glm/vec3.hpp"
namespace fgl::engine
{
struct Frustum;
}
namespace fgl::engine::tree
{
class Chunk;
using ChunkID = std::size_t;
class ChunkManager
{
std::unordered_map< ChunkID, std::shared_ptr< Chunk > > m_chunks {};
std::queue< std::shared_ptr< Chunk > > m_delete_list {};
std::shared_ptr< Chunk > createChunk( const ChunkID id );
//! Deletes any chunks pending deletion
void cleanup();
//! Returns a shared pointer to the chunk with the given ID.
std::shared_ptr< Chunk > getChunk( const ChunkID id );
};
ChunkID getID( const glm::vec3 point );
glm::vec3 getPosition( const ChunkID id );
class Chunk
{
//! Determines if the chunk is active to the rendering system
bool m_rendering_active { true };
const ChunkID m_id;
const glm::vec3 m_center;
//! Contains a list of all objects within this chunk
std::unordered_map< GameObject::GameObjectID, std::shared_ptr< GameObject > > m_objects {};
public:
Chunk() = delete;
Chunk( const ChunkID id );
void addGameObject( std::shared_ptr< GameObject > object );
// Size of a chunk from center to
constexpr static float CHUNK_SIZE { 100.0f };
constexpr static float CHUNK_HALF { CHUNK_SIZE / 2.0f };
//! Returns the number of game objects within this chunk
std::size_t childCount();
//! Returns true if the bounds of this chunk are visible.
bool isVisible( const Frustum& frustum ) const;
};
} // namespace fgl::engine::tree

View File

@@ -28,6 +28,7 @@ namespace fgl::engine
static bool draw_leaf_real_bounds { false };
static bool draw_inview_bounds { false };
static bool draw_branches { false };
static bool draw_model_bounding_boxes { false };
static std::size_t number_moved { 0 };
static std::optional< std::chrono::microseconds > time { std::nullopt };
@@ -40,6 +41,7 @@ namespace fgl::engine
ImGui::Checkbox( "Draw leaf real bounding boxes", &draw_leaf_real_bounds );
ImGui::Checkbox( "Draw ALL in view bounding boxes", &draw_inview_bounds );
ImGui::Checkbox( "Draw branches", &draw_branches );
ImGui::Checkbox( "Draw all model bounding boxes", &draw_model_bounding_boxes );
if ( ImGui::Button( "Reorganize Octtree" ) )
{
@@ -53,7 +55,7 @@ namespace fgl::engine
if ( ImGui::Button( "Recalculate Bounds" ) )
{
const auto start { fgl::Clock::now() };
info.game_objects.recalculateBounds();
info.game_objects.recalculateChildBounds();
const auto end { fgl::Clock::now() };
const auto time_diff { end - start };
time = std::chrono::duration_cast< std::chrono::microseconds >( time_diff );
@@ -120,23 +122,27 @@ namespace fgl::engine
FGL_UNREACHABLE();
}
bool OctTreeNode::contains( const WorldCoordinate coord ) const
{
return this->m_bounds.contains( coord );
}
OctTreeNode& OctTreeNode::operator[]( const WorldCoordinate coord )
OctTreeNode& OctTreeNode::operator[]( const WorldCoordinate coord ) const
{
assert( std::holds_alternative< OctTreeNodeArray >( m_node_data ) );
// Bounding box center
const auto bounds_center { this->m_bounds.getPosition().vec() };
const auto test_dim { glm::greaterThanEqual( coord.vec(), bounds_center ) };
const auto coordinate_center { coord.vec() };
const auto& node_array { std::get< OctTreeNodeArray >( m_node_data ) };
const auto& node { node_array[ test_dim.x ? 1 : 0 ][ test_dim.y ? 1 : 0 ][ test_dim.z ? 1 : 0 ] };
assert( node );
assert( node->canContain( coord ) );
//const auto test_dim { glm::greaterThanEqual( coord.vec(), bounds_center ) };
//const auto& node_array { std::get< OctTreeNodeArray >( m_node_data ) };
//const auto& node { node_array[ test_dim.x ? 1 : 0 ][ test_dim.y ? 1 : 0 ][ test_dim.z ? 1 : 0 ] };
const std::size_t x_idx { coordinate_center.x > bounds_center.x ? 1ul : 0ul };
const std::size_t y_idx { coordinate_center.y > bounds_center.y ? 1ul : 0ul };
const std::size_t z_idx { coordinate_center.z > bounds_center.z ? 1ul : 0ul };
auto& node { std::get< OctTreeNodeArray >( m_node_data )[ x_idx ][ y_idx ][ z_idx ] };
FGL_ASSERT( node, "Node was invalid!" );
FGL_ASSERT( node->canContain( coord ), "Node was not capable of containing the object!" );
return *node.get();
}
@@ -210,7 +216,9 @@ namespace fgl::engine
const bool is_forward { obj_coordinate.y > center.y };
const bool is_up { obj_coordinate.z > center.z };
const std::unique_ptr< OctTreeNode >& node { new_nodes[ is_right ][ is_forward ][ is_up ] };
const std::unique_ptr< OctTreeNode >& node {
new_nodes[ is_right ? 1 : 0 ][ is_forward ? 1 : 0 ][ is_up ? 1 : 0 ]
};
assert( std::holds_alternative< OctTreeNodeLeaf >( node->m_node_data ) );
std::get< OctTreeNodeLeaf >( node->m_node_data ).emplace_back( std::move( obj ) );
@@ -218,6 +226,8 @@ namespace fgl::engine
this->m_node_data = std::move( new_nodes );
recalculateChildBounds();
if ( depth - 1 >= 1 )
{
split( depth );
@@ -240,9 +250,11 @@ namespace fgl::engine
return node;
}
const bool should_recalc_bounds { obj.hasComponent< ModelComponent >() };
objects.emplace_back( std::move( obj ) );
recalculateBounds();
if ( should_recalc_bounds ) recalculateLeafBounds();
return this;
}
@@ -272,15 +284,9 @@ namespace fgl::engine
{
std::size_t sum { 0 };
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 )
{
sum += std::get< OctTreeNodeArray >( m_node_data )[ x ][ y ][ z ]->itemCount();
}
}
sum += std::get< OctTreeNodeArray >( m_node_data )[ x ][ y ][ z ]->itemCount();
}
return sum;
@@ -299,6 +305,11 @@ namespace fgl::engine
return std::get< OctTreeNodeLeaf >( m_node_data );
}
OctTreeNodeLeaf& OctTreeNode::getLeaf()
{
return std::get< OctTreeNodeLeaf >( m_node_data );
}
bool OctTreeNode::isInFrustum( const Frustum& frustum ) const
{
#if ENABLE_IMGUI
@@ -310,6 +321,23 @@ namespace fgl::engine
debug::drawBoundingBox( m_fit_bounding_box );
if ( draw_leaf_real_bounds ) [[unlikely]]
debug::drawBoundingBox( m_bounds );
if ( draw_model_bounding_boxes ) [[unlikely]]
{
for ( const auto& obj : getLeaf() )
{
const Matrix< MatrixType::ModelToWorld > obj_transform { obj.getTransform().mat() };
for ( const auto* model : obj.getComponents< ModelComponent >() )
{
const auto model_bounds { ( *model )->getBoundingBox() };
const Matrix< MatrixType::ModelToWorld > model_transform { model->m_transform.mat() };
const auto combined_transform { obj_transform * model_transform };
debug::drawBoundingBox( combined_transform * model_transform );
}
}
}
}
return true;
@@ -334,10 +362,17 @@ namespace fgl::engine
*/
void OctTreeNode::recalculateBounds()
{
if ( isLeaf() )
return recalculateLeafBounds();
else if ( isBranch() )
return recalculateNodeBounds();
if ( isBranch() ) [[likely]]
{
recalculateNodeBounds();
return;
}
else
{
FGL_ASSERT( isLeaf(), "Expected leaf, Got whatever the fuck this is instead" );
recalculateLeafBounds();
return;
}
FGL_UNREACHABLE();
}
@@ -390,6 +425,22 @@ namespace fgl::engine
void OctTreeNode::drawDebug() const
{}
void OctTreeNode::recalculateChildBounds()
{
if ( isBranch() )
{
FOR_EACH_OCTTREE_NODE
{
auto& node { std::get< OctTreeNodeArray >( m_node_data )[ x ][ y ][ z ] };
node->recalculateChildBounds();
}
}
else
{
recalculateBounds();
}
}
OctTreeNode* OctTreeNode::findID( const GameObject::GameObjectID id )
{
ZoneScoped;
@@ -435,9 +486,18 @@ namespace fgl::engine
return canContain( obj.getTransform().translation );
}
bool OctTreeNode::canContain( const WorldCoordinate& obj ) const
bool OctTreeNode::canContain( const WorldCoordinate& coord ) const
{
return m_bounds.contains( obj );
const auto center { this->getCenter() };
// top right forward
const auto high_center { center.vec() + glm::vec3( this->m_bounds.scale() ) };
// bottom left back
const auto low_center { center.vec() - glm::vec3( this->m_bounds.scale() ) };
const bool under_high_center { glm::all( glm::lessThanEqual( coord.vec(), high_center ) ) };
const bool above_low_center { glm::all( glm::greaterThan( coord.vec(), low_center ) ) };
return under_high_center && above_low_center;
}
GameObject OctTreeNode::extract( const GameObject::GameObjectID id )
@@ -547,7 +607,7 @@ namespace fgl::engine
}
// if ( isBoundsExpanded() && m_parent )
if ( m_parent ) m_parent->recalculateBounds();
if ( m_parent != nullptr ) m_parent->recalculateBounds();
}
void OctTreeNode::recalculateLeafBounds()
@@ -555,21 +615,18 @@ namespace fgl::engine
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;
}
m_fit_bounding_box = static_cast< AxisAlignedBoundingBox< CoordinateSpace::World > >( m_bounds );
if ( data.empty() ) 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 )
for ( const ModelComponent* model : game_object.getComponents< ModelComponent >() )
{
const OrientedBoundingBox< CS::Model > model_bounding_box { ( *model )->getBoundingBox() };
@@ -583,7 +640,7 @@ namespace fgl::engine
const auto aligned_bounding_box { world_bounding_box.alignToWorld() };
if ( fit_set )
if ( fit_set ) [[likely]]
m_fit_bounding_box = m_fit_bounding_box.combine( aligned_bounding_box );
else
{
@@ -595,7 +652,7 @@ namespace fgl::engine
// Have our parent recalculate its bounds
// if ( isBoundsExpanded() && m_parent )
if ( m_parent ) m_parent->recalculateBounds();
if ( m_parent != nullptr ) m_parent->recalculateBounds();
}
} // namespace fgl::engine

View File

@@ -66,6 +66,7 @@ namespace fgl::engine
WorldCoordinate getCenter() const;
WorldCoordinate getFitCenter() const;
void drawDebug() const;
void recalculateChildBounds();
private:
@@ -97,9 +98,7 @@ namespace fgl::engine
void getAllLeafs( std::vector< OctTreeNodeLeaf* >& out_leafs );
void getAllLeafsInFrustum( const Frustum& frustum, std::vector< OctTreeNodeLeaf* >& out_leafs );
bool contains( WorldCoordinate coord ) const;
OctTreeNode& operator[]( const WorldCoordinate coord );
OctTreeNode& operator[]( const WorldCoordinate coord ) const;
public:
@@ -129,6 +128,7 @@ namespace fgl::engine
std::size_t itemCount() const;
const OctTreeNodeArray& getBranches() const;
const OctTreeNodeLeaf& getLeaf() const;
OctTreeNodeLeaf& getLeaf();
};
#define FOR_EACH_OCTTREE_NODE \