10#include <glm/gtc/matrix_transform.hpp>
15 std::function<glm::mat4()>
base;
16 std::vector<std::shared_ptr<glm::mat4>>
layers;
21 struct StackedSource {
22 std::shared_ptr<PlacementStack>
stack;
24 glm::mat4 operator()()
const
26 glm::mat4 placed =
stack->base ?
stack->base() : glm::mat4(1.0F);
27 for (
const auto& layer :
stack->layers) {
28 placed = *layer * placed;
34 std::shared_ptr<PlacementStack> stack_of(
const std::shared_ptr<Buffers::RenderProcessor>& proc)
36 const auto&
source = proc->get_geometry_transform_source();
37 const auto* stacked =
source ?
source.target<StackedSource>() : nullptr;
38 return stacked ? stacked->stack :
nullptr;
41 glm::quat frame(
const std::optional<glm::quat>& orientation)
43 return orientation.value_or(glm::quat(1.0F, 0.0F, 0.0F, 0.0F));
46 std::vector<std::shared_ptr<Buffers::RenderProcessor>> render_processors(
47 const std::shared_ptr<Buffers::VKBuffer>& buf)
49 std::vector<std::shared_ptr<Buffers::RenderProcessor>> processors;
50 if (
auto primary = buf->get_render_processor()) {
51 processors.push_back(std::move(primary));
53 for (
auto& proc : buf->get_additional_render_processors()) {
54 processors.push_back(std::move(proc));
59 void place(Attachment& attachment,
const std::shared_ptr<Buffers::RenderProcessor>& proc)
61 const bool known = std::ranges::any_of(attachment.followed,
62 [&proc](
const auto& entry) { return entry.first == proc; });
67 auto stack = stack_of(proc);
69 stack = std::make_shared<PlacementStack>();
70 stack->base = proc->get_geometry_transform_source();
72 if (
const auto& fixed = proc->get_geometry_transform()) {
73 stack->base = [m = *fixed] {
return m; };
76 proc->set_geometry_transform_source(StackedSource {
stack });
79 stack->layers.push_back(attachment.transform);
80 attachment.followed.emplace_back(proc, std::move(
stack));
86 std::shared_ptr<Buffers::VKBuffer> buf,
88 const std::optional<glm::quat>& orientation)
91 .
buf = std::move(buf),
93 .transform = std::make_shared<glm::mat4>(1.0F),
97 attachment.anchor = *anchor;
100 "Attachment anchors at the buffer's local origin: no geometry could be read from it");
103 attachment.applied = attachment.anchor + frame(orientation) * config.
offset;
110 const std::optional<glm::quat>& orientation)
112 const glm::quat rotation = frame(orientation);
113 glm::vec3 placed = glm::vec3(*attachment.
transform * glm::vec4(attachment.
anchor, 1.0F));
118 *attachment.
transform = glm::translate(glm::mat4(1.0F), delta) * *attachment.
transform;
121 attachment.
config.
offset += glm::inverse(rotation) * delta;
132 const std::optional<glm::quat>& orientation)
134 const glm::quat rotation = frame(orientation);
137 attachment.
anchor = *anchor;
140 "recenter kept the previous anchor: no geometry could be read from the buffer");
143 const glm::vec3 placed = glm::vec3(*attachment.
transform * glm::vec4(attachment.
anchor, 1.0F));
167 for (
const auto& proc : render_processors(attachment.
buf)) {
168 place(attachment, proc);
176 if (
stack->layers.empty() && stack_of(proc) ==
stack) {
177 proc->set_geometry_transform_source(std::move(
stack->base));
#define MF_WARN(comp, ctx,...)
std::shared_ptr< PlacementStack > stack
std::optional< glm::vec3 > position
@ Init
Engine/subsystem initialization.
@ Runtime
General runtime operations (default fallback)
@ Nexus
Spatial indexing and scheduling for user-defined behaviour.
glm::mat4 pivot_transform(const glm::vec3 &pivot, const glm::vec3 &target, const glm::quat &rotation)
Rigid transform that rotates about a local pivot and lands the pivot on a world point.
AABB2D place(AABB2D anchor, Side side, float w, float h, float gap=0.F, Align align=Align::Center) noexcept
Compute a region of size (w, h) positioned relative to anchor.
std::optional< glm::vec3 > read_anchor(const std::shared_ptr< Buffers::VKBuffer > &buf, const std::optional< uint32_t > &index)
Anchor of a buffer's geometry in its own stored coordinates.
void apply_attachment(Attachment &attachment, const InfluenceContext &ctx)
Rebuild the transform from ctx and place every render processor of the buffer.
void recenter_attachment(Attachment &attachment, std::optional< glm::vec3 > &position, const std::optional< glm::quat > &orientation)
Read the buffer's geometry again and move the anchor to match.
void place_attachment(Attachment &attachment)
Place every render processor of the buffer that is not placed yet.
void follow_attachment(Attachment &attachment, std::optional< glm::vec3 > &position, const std::optional< glm::quat > &orientation)
Set position from the buffer, or fold an outside move into the attachment.
void release_attachment(Attachment &attachment)
Give every placed render processor back the geometry transform it had.
Attachment make_attachment(std::shared_ptr< Buffers::VKBuffer > buf, const AttachConfig &config, const std::optional< glm::quat > &orientation)
Build an attachment to buf.
std::optional< uint32_t > index
Vertex whose position anchors the Agent.
glm::vec3 offset
Offset of the Agent from the anchor, in the Agent's own frame.
@ Carry
The buffer is moved along with the Agent.
How an Agent attaches to a buffer that already exists.
std::shared_ptr< Buffers::VKBuffer > buf
std::shared_ptr< glm::mat4 > transform
std::vector< std::pair< std::shared_ptr< Buffers::RenderProcessor >, std::shared_ptr< PlacementStack > > > followed
State of one Agent attached to an existing buffer.
glm::vec3 position
Position of the influence point in world space.
std::optional< glm::quat > orientation
Optional orientation of the influencer. Local +Z is its forward direction.
Data passed to an Emitter or Agent influence function on each commit.
std::vector< std::shared_ptr< glm::mat4 > > layers
std::function< glm::mat4()> base
The placements layered on one render processor, kept by its geometry transform source.