#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace boundard::render { struct InputEvent { enum class Type { Key, MouseButton, CursorMove, Scroll, }; enum class Action { Release = 0, Press = 1, Repeat = 2, }; Type type = Type::Key; Action action = Action::Press; int key = -1; int scancode = -1; int mods = 0; int button = -1; double x = 0.0; double y = 0.0; }; class Renderer { public: Renderer(); ~Renderer(); Renderer(const Renderer&) = delete; Renderer& operator=(const Renderer&) = delete; Renderer(Renderer&&) = delete; Renderer& operator=(Renderer&&) = delete; void init(int width, int height, const char* title); void draw(const Actor* const* actors, size_t actor_count); bool should_close() const; void poll_events() const; using InputCallback = std::function; void set_input_callback(InputCallback callback); bool is_key_down(int key) const; bool is_mouse_button_down(int button) const; std::array cursor_position() const; void destroy(); private: struct Impl; Impl* impl_; }; // 类似 Godot InputMap 的按键动作绑定。 class InputMap { public: void add_action(const std::string& action); void bind_key(const std::string& action, int key); void unbind_key(const std::string& action, int key); void bind_mouse_button(const std::string& action, int button); void unbind_mouse_button(const std::string& action, int button); void handle_event(const InputEvent& event); void end_frame(); bool is_action_pressed(const std::string& action) const; bool is_action_just_pressed(const std::string& action) const; bool is_action_just_released(const std::string& action) const; float get_action_strength(const std::string& action) const; float get_axis(const std::string& negative_action, const std::string& positive_action) const; private: struct ActionState { std::unordered_set keys; std::unordered_set mouse_buttons; std::unordered_map held_keys; std::unordered_map held_buttons; size_t held_key_count = 0; size_t held_button_count = 0; bool pressed = false; bool just_pressed = false; bool just_released = false; }; mutable std::mutex mutex_; std::unordered_map actions_; }; // 渲染线程包装:主线程更新 Actor,渲染线程持续读取并提交绘制。 class RenderLoop { public: RenderLoop() = default; ~RenderLoop(); RenderLoop(const RenderLoop&) = delete; RenderLoop& operator=(const RenderLoop&) = delete; RenderLoop(RenderLoop&&) = delete; RenderLoop& operator=(RenderLoop&&) = delete; void start(int width, int height, const char* title); void stop(); void set_actors(std::vector actors); void poll_events() const; bool should_close() const; InputMap& input(); const InputMap& input() const; private: void run(); Renderer renderer_; InputMap input_map_; std::thread thread_; std::atomic running_{false}; mutable std::mutex actors_mutex_; std::vector actors_; }; } // namespace boundard::render