#pragma once #include #include #include #include "render/Renderer.h" #include "InteractiveObjectState.h" #include namespace FRG { class Renderer; struct LoadedGameObject { std::string name; // identity key — stays at top level LoadedGameObjectState creationInfo; // paths + transforms for save/recreate std::shared_ptr texture; std::shared_ptr textureDarklands; VertexRenderStruct mesh; }; struct InteractiveObject { explicit InteractiveObject(InteractiveObjectState& boundState) : state(boundState) {} std::string id; LoadedGameObject loadedObject; // rendering assets // Factory: creates a fully-loaded InteractiveObject from a state descriptor. // Loads textures and centers the mesh around the state position. static InteractiveObject createFromState(InteractiveObjectState& state, Renderer& renderer, const std::string& zipPath = ""); void draw(Renderer& renderer) const; void drawDarklands(Renderer& renderer) const; void drawShadowDepth(Renderer& renderer) const; void capturePresentationState(); const std::string& entityId() const { return id; } private: friend class GameObjectLoader; friend class Location; friend class LocationEditor; friend class ScriptEngine; InteractiveObjectState& state; // non-owning binding to LocationGameState struct PresentationSample { Eigen::Vector3f position = Eigen::Vector3f::Zero(); float rotationY = 0.f; float scale = 1.f; float alpha = 1.f; bool isActive = true; }; PresentationSample previousPresentationSample_; PresentationSample currentPresentationSample_; std::chrono::steady_clock::time_point lastPresentationUpdate_; bool hasPresentationSample_ = false; PresentationSample interpolatedPresentationState() const; }; } // namespace FRG