#include "carry_system.hpp" #include "entities/camera.hpp" namespace Nimbin { bool CarriedLine::empty() const { return size == 0; } void CarriedLine::push(Text::TokenPtr w) { CarriedWordNodePtr node = cpputils::make_unique(std::move(w)); node->prev = last; if (!first) { first = std::move(node); last = first.get(); } else { last->next = std::move(node); last = last->next.get(); } size++; } Text::TokenPtr CarriedLine::pop_back() { while (last && !last->word) { if (last->prev) { last = last->prev; last->next.reset(); } else { first.reset(); last = nullptr; } size--; } if (!last) return nullptr; Text::TokenPtr word = std::move(last->word); if (last->prev) { last = last->prev; last->next.reset(); } else { first.reset(); last = nullptr; } size--; return word; } Text::TokenPtr CarriedLine::pop_front() { if (!first) return nullptr; Text::TokenPtr word = std::move(first->word); if (first->next) { first = std::move(first->next); first->prev = nullptr; } else { first.reset(); last = nullptr; } size--; return word; } DynArray CarriedLine::nodes() const { DynArray result; for (CarriedWordNode* node = first.get(); node; node = node->next.get()) result.push_back(node); return result; } DynArray CarriedLine::reverse_nodes() const { DynArray result; for (CarriedWordNode* node = last; node; node = node->prev) result.push_back(node); return result; } void CarriedLine::clear() { first.reset(); last = nullptr; size = 0; } void CarriedLine::compact() { DynArray survivors; for (CarriedWordNode* node = first.get(); node; node = node->next.get()) if (node->word) survivors.push_back(std::move(node->word)); clear(); for (Text::TokenPtr& w : survivors) push(std::move(w)); } Vec3 CarriedLine::get_LineAnchor(const Camera& camera, double carry_dist) { const Vec3& right = camera.right; const Vec3 up = Math::cross(camera.right, camera.fwd); return { camera.pos.x + camera.fwd.x * carry_dist + right.x * Config::Carry::hand_right - up.x * Config::Carry::hand_down, camera.pos.y + camera.fwd.y * carry_dist + right.y * Config::Carry::hand_right - up.y * Config::Carry::hand_down, camera.pos.z + camera.fwd.z * carry_dist + right.z * Config::Carry::hand_right - up.z * Config::Carry::hand_down }; } DynArray CarriedLine::get_SlotPosition(const Vec3& anchor, const Vec3& right, double carry_gap) { DynArray positions; DynArray nodes = reverse_nodes(); if (nodes.empty()) return positions; double current_offset = 0.0; for (size_t i = 0; i < nodes.size(); i++) { if (!nodes[i]->word) continue; positions.push_back({ anchor.x + right.x * current_offset, anchor.y + right.y * current_offset, anchor.z + right.z * current_offset }); if (i + 1 < nodes.size() && nodes[i + 1]->word) { double half_extent_curr = 0.5, half_extent_next = 0.5; if (nodes[i]->word->type == ObjectType::Text) half_extent_curr = static_cast(*nodes[i]->word).half_extent; else half_extent_curr = nodes[i]->word->shape.half_extents.x; if (nodes[i+1]->word->type == ObjectType::Text) half_extent_next = static_cast(*nodes[i+1]->word).half_extent; else half_extent_next = nodes[i+1]->word->shape.half_extents.x; current_offset -= (half_extent_curr + half_extent_next + carry_gap); } } return positions; } } // namespace Nimbin