Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions subprojects/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*/
!patches/
!packagefiles/

# Auto-generated wrap-redirects from transitive deps
lua.wrap
Expand Down
11 changes: 11 additions & 0 deletions subprojects/packagefiles/sigslot/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
project('sigslot', 'cpp',
version: '1.2.3',
license: 'MIT',
default_options: ['cpp_std=c++14'])

thread_dep = dependency('threads')

sigslot_dep = declare_dependency(
include_directories: include_directories('include'),
dependencies: thread_dep,
)
7 changes: 7 additions & 0 deletions subprojects/sigslot.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[wrap-git]
url = https://github.com/palacaze/sigslot.git
revision = v1.2.3
patch_directory = sigslot

[provide]
sigslot = sigslot_dep
15 changes: 12 additions & 3 deletions visualization/include/balsa/scene_graph/AbstractFeature.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#if !defined(BALSA_SCENE_GRAPH_ABSTRACT_FEATURE_HPP)
#define BALSA_SCENE_GRAPH_ABSTRACT_FEATURE_HPP

#include <sigslot/signal.hpp>

namespace balsa::scene_graph {

class Object;
Expand All @@ -18,8 +20,15 @@ class AbstractFeature {
public:
virtual ~AbstractFeature() = default;

Object &object() { return *_object; }
const Object &object() const { return *_object; }
auto object() -> Object & { return *_object; }
auto object() const -> const Object & { return *_object; }

// Signal emitted when this feature's data has changed.
// Subscribers receive a reference to the modified feature.
sigslot::signal_st<AbstractFeature &> on_modified;

// Call this from derived classes after mutating internal state.
auto mark_modified() -> void { on_modified(*this); }

protected:
AbstractFeature() = default;
Expand All @@ -34,6 +43,6 @@ class AbstractFeature {
Object *_object = nullptr;
};

}// namespace balsa::scene_graph
} // namespace balsa::scene_graph

#endif
91 changes: 91 additions & 0 deletions visualization/include/balsa/scene_graph/FeatureIndex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#if !defined(BALSA_SCENE_GRAPH_FEATUREINDEX_HPP)
#define BALSA_SCENE_GRAPH_FEATUREINDEX_HPP

#include <span>
#include <typeindex>
#include <unordered_map>
#include <vector>

#include <sigslot/signal.hpp>

#include "AbstractFeature.hpp"
#include "Object.hpp"

namespace balsa::scene_graph {

// ── FeatureIndex ────────────────────────────────────────────────────
//
// Maintains a scene-level index that maps feature types to the set of
// Objects that carry a feature of that type. Subscribes to Object
// signals (on_feature_added, on_feature_removing, on_child_added,
// on_child_removing) so the index stays up to date automatically.
//
// Usage:
// FeatureIndex index;
// index.track(root); // recursively subscribe to root + all descendants
//
// auto meshes = index.objects_with<MeshData>(); // O(1) lookup
// for (Object* obj : meshes) { ... }
//
// Inherits sigslot::observer_st so that all signal connections are
// automatically severed when the FeatureIndex is destroyed.

class FeatureIndex : public sigslot::observer_st {
public:
FeatureIndex() = default;
~FeatureIndex() override = default;

// Non-copyable, non-movable (observer_st manages connections).
FeatureIndex(const FeatureIndex &) = delete;
FeatureIndex &operator=(const FeatureIndex &) = delete;
FeatureIndex(FeatureIndex &&) = delete;
FeatureIndex &operator=(FeatureIndex &&) = delete;

// Recursively subscribe to an Object and all its current
// descendants. Indexes every feature already present.
auto track(Object &root) -> void;

// Stop tracking an Object (and its descendants).
auto untrack(Object &root) -> void;

// Return all Objects that currently carry a feature of type F.
template <typename F>
auto objects_with() const -> std::span<Object *const>;

// Return the count of Objects carrying feature type F.
template <typename F>
auto count() const -> std::size_t;

private:
auto track_single(Object &obj) -> void;
auto untrack_single(Object &obj) -> void;

// Signal handlers.
auto on_feature_added(Object &obj, AbstractFeature &feature) -> void;
auto on_feature_removing(Object &obj, AbstractFeature &feature) -> void;
auto on_child_added(Object &parent, Object &child) -> void;
auto on_child_removing(Object &parent, Object &child) -> void;

// type_index -> vector of Object pointers carrying that feature type.
std::unordered_map<std::type_index, std::vector<Object *>> _index;
};

// ── Template implementations ────────────────────────────────────────

template <typename F>
auto FeatureIndex::objects_with() const -> std::span<Object *const> {
auto it = _index.find(std::type_index(typeid(F)));
if (it == _index.end()) return {};
return it->second;
}

template <typename F>
auto FeatureIndex::count() const -> std::size_t {
auto it = _index.find(std::type_index(typeid(F)));
if (it == _index.end()) return 0;
return it->second.size();
}

} // namespace balsa::scene_graph

#endif
Loading
Loading