399 lines
13 KiB
C++
399 lines
13 KiB
C++
#pragma once
|
|
#include "../base/Geometry.h"
|
|
#include "../base/Memory.h"
|
|
#include "../base/Object_Semantics.h"
|
|
#include "../event/Event.h"
|
|
#include "../event/Key_Event.h"
|
|
#include "../event/Pointer_Event.h"
|
|
#include "../event/Resize_Event.h"
|
|
#include "../event/Wheel_Event.h"
|
|
#include "Render_Config.h"
|
|
#include "Update_Completion.h"
|
|
#include "global.h"
|
|
#include <concepts>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <memory_resource>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace renderive {
|
|
|
|
class Canvas;
|
|
struct Render_Frame_Snapshot;
|
|
class Renderable;
|
|
class Renderable_Runtime;
|
|
|
|
struct Input_Data {
|
|
virtual ~Input_Data() = default;
|
|
virtual void clear() {}
|
|
virtual void consume() {
|
|
clear();
|
|
}
|
|
};
|
|
|
|
struct Latest_Input_Data : Input_Data {
|
|
bool pending = false;
|
|
|
|
void mark_latest_pushed() {
|
|
pending = true;
|
|
}
|
|
|
|
void clear_latest() {
|
|
pending = false;
|
|
}
|
|
};
|
|
|
|
struct Render_State {
|
|
virtual ~Render_State() = default;
|
|
std::uint64_t version = 0;
|
|
};
|
|
|
|
struct Hit_Testable {
|
|
virtual ~Hit_Testable() = default;
|
|
virtual bool select_test(const PointF& pos) = 0;
|
|
};
|
|
|
|
struct Pointer_Interactive {
|
|
virtual ~Pointer_Interactive() = default;
|
|
virtual void mouse_press_event(const Pointer_Event& event) = 0;
|
|
virtual void mouse_move_event(const Pointer_Event& event) = 0;
|
|
virtual void mouse_release_event(const Pointer_Event& event) = 0;
|
|
};
|
|
|
|
struct Wheel_Interactive {
|
|
virtual ~Wheel_Interactive() = default;
|
|
virtual void wheel_event(const Wheel_Event& event) = 0;
|
|
};
|
|
|
|
struct Key_Press_Interactive {
|
|
virtual ~Key_Press_Interactive() = default;
|
|
virtual void key_press_event(const Key_Event& event) = 0;
|
|
};
|
|
|
|
struct Key_Release_Interactive {
|
|
virtual ~Key_Release_Interactive() = default;
|
|
virtual void key_release_event(const Key_Event& event) = 0;
|
|
};
|
|
|
|
struct Hover_Interactive {
|
|
virtual ~Hover_Interactive() = default;
|
|
virtual void set_hover_state(Point pos, bool active) = 0;
|
|
};
|
|
|
|
struct Render_Object_Owner : Move_Only {
|
|
Render_Object_Owner() noexcept = default;
|
|
|
|
Render_Object_Owner(void* pointer, std::pmr::memory_resource* resource, void (*destroy)(void*, std::pmr::memory_resource*)) noexcept
|
|
: pointer(pointer), resource(resource), destroy(destroy) {}
|
|
|
|
Render_Object_Owner(Render_Object_Owner&& other) noexcept
|
|
: pointer(std::exchange(other.pointer, nullptr)),
|
|
resource(std::exchange(other.resource, nullptr)),
|
|
destroy(std::exchange(other.destroy, nullptr)) {}
|
|
|
|
Render_Object_Owner& operator=(Render_Object_Owner&& other) noexcept {
|
|
if (this == &other)
|
|
return *this;
|
|
reset();
|
|
pointer = std::exchange(other.pointer, nullptr);
|
|
resource = std::exchange(other.resource, nullptr);
|
|
destroy = std::exchange(other.destroy, nullptr);
|
|
return *this;
|
|
}
|
|
|
|
~Render_Object_Owner() {
|
|
reset();
|
|
}
|
|
|
|
template <typename T>
|
|
T* get() const {
|
|
return static_cast<T*>(pointer);
|
|
}
|
|
|
|
void reset() noexcept {
|
|
if (!pointer)
|
|
return;
|
|
destroy(pointer, resource);
|
|
pointer = nullptr;
|
|
resource = nullptr;
|
|
destroy = nullptr;
|
|
}
|
|
|
|
explicit operator bool() const noexcept {
|
|
return pointer != nullptr;
|
|
}
|
|
|
|
void* pointer{};
|
|
std::pmr::memory_resource* resource{};
|
|
void (*destroy)(void*, std::pmr::memory_resource*){};
|
|
};
|
|
|
|
template <typename T, typename... Args>
|
|
Render_Object_Owner make_render_object(Args&&... args) {
|
|
std::pmr::memory_resource* resource = memory_resource(Memory_Domain::Renderable);
|
|
std::pmr::polymorphic_allocator<T> allocator(resource);
|
|
T* pointer = allocator.allocate(1);
|
|
try {
|
|
std::construct_at(pointer, std::forward<Args>(args)...);
|
|
}
|
|
catch (...) {
|
|
allocator.deallocate(pointer, 1);
|
|
throw;
|
|
}
|
|
return Render_Object_Owner(pointer, resource, [](void* object, std::pmr::memory_resource* resource) {
|
|
std::pmr::polymorphic_allocator<T> allocator(resource);
|
|
std::destroy_at(static_cast<T*>(object));
|
|
allocator.deallocate(static_cast<T*>(object), 1);
|
|
});
|
|
}
|
|
|
|
struct Render_State_Read_Handle {
|
|
virtual ~Render_State_Read_Handle() = default;
|
|
};
|
|
|
|
struct Render_State_Write_Handle {
|
|
virtual ~Render_State_Write_Handle() = default;
|
|
};
|
|
|
|
struct Render_Input_Write_Handle {
|
|
virtual ~Render_Input_Write_Handle() = default;
|
|
virtual void set_completion(std::shared_ptr<Update_State> state) {
|
|
(void)state;
|
|
}
|
|
};
|
|
|
|
struct Render_Input_Frame_Handle {
|
|
virtual ~Render_Input_Frame_Handle() = default;
|
|
virtual void consume_input(Input_Data* input) {
|
|
if (input)
|
|
input->consume();
|
|
}
|
|
};
|
|
|
|
struct Render_State_Read_Guard : Move_Only {
|
|
Render_State_Read_Guard() = default;
|
|
Render_State_Read_Guard(Render_State* state, std::unique_ptr<Render_State_Read_Handle> handle)
|
|
: state(state), handle(std::move(handle)) {}
|
|
Render_State_Read_Guard(Render_State_Read_Guard&&) noexcept = default;
|
|
Render_State_Read_Guard& operator=(Render_State_Read_Guard&&) noexcept = default;
|
|
~Render_State_Read_Guard() = default;
|
|
|
|
explicit operator bool() const noexcept {
|
|
return state && handle;
|
|
}
|
|
|
|
Render_State* state{};
|
|
std::unique_ptr<Render_State_Read_Handle> handle;
|
|
};
|
|
|
|
struct Render_State_Write_Guard : Move_Only {
|
|
Render_State_Write_Guard() = default;
|
|
Render_State_Write_Guard(Render_State* state, std::unique_ptr<Render_State_Write_Handle> handle)
|
|
: state(state), handle(std::move(handle)) {}
|
|
Render_State_Write_Guard(Render_State_Write_Guard&&) noexcept = default;
|
|
Render_State_Write_Guard& operator=(Render_State_Write_Guard&&) noexcept = default;
|
|
~Render_State_Write_Guard() = default;
|
|
|
|
explicit operator bool() const noexcept {
|
|
return state && handle;
|
|
}
|
|
|
|
Render_State* state{};
|
|
std::unique_ptr<Render_State_Write_Handle> handle;
|
|
};
|
|
|
|
struct Render_Input_Write_Guard : Move_Only {
|
|
Render_Input_Write_Guard() = default;
|
|
Render_Input_Write_Guard(Input_Data* input, std::unique_ptr<Render_Input_Write_Handle> handle)
|
|
: input(input), handle(std::move(handle)) {}
|
|
Render_Input_Write_Guard(Render_Input_Write_Guard&&) noexcept = default;
|
|
Render_Input_Write_Guard& operator=(Render_Input_Write_Guard&&) noexcept = default;
|
|
~Render_Input_Write_Guard() = default;
|
|
|
|
explicit operator bool() const noexcept {
|
|
return input && handle;
|
|
}
|
|
|
|
Input_Data* input{};
|
|
std::unique_ptr<Render_Input_Write_Handle> handle;
|
|
|
|
void set_completion(std::shared_ptr<Update_State> state) {
|
|
if (handle)
|
|
handle->set_completion(std::move(state));
|
|
}
|
|
};
|
|
|
|
struct Render_Input_Frame_Guard : Move_Only {
|
|
Render_Input_Frame_Guard() = default;
|
|
Render_Input_Frame_Guard(Input_Data* input, std::unique_ptr<Render_Input_Frame_Handle> handle)
|
|
: input(input), handle(std::move(handle)) {}
|
|
Render_Input_Frame_Guard(Render_Input_Frame_Guard&&) noexcept = default;
|
|
Render_Input_Frame_Guard& operator=(Render_Input_Frame_Guard&&) noexcept = default;
|
|
~Render_Input_Frame_Guard() = default;
|
|
|
|
explicit operator bool() const noexcept {
|
|
return input && handle;
|
|
}
|
|
|
|
Input_Data* input{};
|
|
std::unique_ptr<Render_Input_Frame_Handle> handle;
|
|
|
|
void consume_input() const {
|
|
if (handle)
|
|
handle->consume_input(input);
|
|
}
|
|
};
|
|
|
|
enum class Renderable_State_Role : std::uint8_t {
|
|
Edit,
|
|
Ready,
|
|
Render
|
|
};
|
|
|
|
enum class Renderable_Input_Role : std::uint8_t {
|
|
Edit,
|
|
Ready,
|
|
Render
|
|
};
|
|
|
|
struct Renderable_Frame_View : Move_Only {
|
|
Renderable_Frame_View() = default;
|
|
Renderable_Frame_View(Render_State_Read_Guard state_guard, Render_Input_Frame_Guard input_guard)
|
|
: state(state_guard.state),
|
|
input(input_guard.input),
|
|
state_guard(std::move(state_guard)),
|
|
input_guard(std::move(input_guard)) {}
|
|
Renderable_Frame_View(Renderable_Frame_View&&) noexcept = default;
|
|
Renderable_Frame_View& operator=(Renderable_Frame_View&&) noexcept = default;
|
|
~Renderable_Frame_View() = default;
|
|
|
|
explicit operator bool() const noexcept {
|
|
return state && state_guard;
|
|
}
|
|
|
|
Render_State* state{};
|
|
Input_Data* input{};
|
|
Render_State_Read_Guard state_guard;
|
|
Render_Input_Frame_Guard input_guard;
|
|
|
|
void consume_input() const {
|
|
input_guard.consume_input();
|
|
}
|
|
};
|
|
|
|
class Renderable_Runtime {
|
|
public:
|
|
using Copy_Render_State_Function = std::function<void(Render_State&, const Render_State&)>;
|
|
|
|
virtual ~Renderable_Runtime() = default;
|
|
virtual void set_render_state_copier(Copy_Render_State_Function copier) = 0;
|
|
virtual void cancel_pending_completions() = 0;
|
|
virtual void drain_committed_update_states(std::pmr::vector<std::shared_ptr<Update_State>>& output) = 0;
|
|
virtual Render_State_Read_Guard acquire_state_read(Renderable_State_Role role) = 0;
|
|
virtual Render_State_Read_Guard acquire_render_state_read() = 0;
|
|
virtual Render_State_Read_Guard acquire_edit_state_read() = 0;
|
|
virtual Render_State_Write_Guard acquire_edit_state() = 0;
|
|
virtual Render_Input_Write_Guard acquire_edit_input(bool notify_render) = 0;
|
|
virtual Render_Input_Frame_Guard acquire_input_read(Renderable_Input_Role role) = 0;
|
|
virtual Renderable_Frame_View capture_frame_view() = 0;
|
|
virtual Render_State* state(Renderable_State_Role role) = 0;
|
|
virtual Input_Data* input_data(Renderable_Input_Role role) = 0;
|
|
virtual void clear_render_input() = 0;
|
|
};
|
|
|
|
struct Render_Data {
|
|
Renderable* q_ptr{};
|
|
|
|
virtual void initialize_runtime(std::unique_ptr<Renderable_Runtime> runtime) = 0;
|
|
virtual void cancel_pending_completions() = 0;
|
|
virtual void drain_committed_update_states(std::pmr::vector<std::shared_ptr<Update_State>>& output) = 0;
|
|
virtual Render_State_Read_Guard acquire_state_read(Renderable_State_Role role) = 0;
|
|
virtual Render_State_Read_Guard acquire_render_state_read() = 0;
|
|
virtual Render_State_Read_Guard acquire_edit_state_read() = 0;
|
|
virtual Render_State_Write_Guard acquire_edit_state() = 0;
|
|
virtual Render_Input_Write_Guard acquire_edit_input(bool notify_render) = 0;
|
|
virtual Render_Input_Frame_Guard acquire_input_read(Renderable_Input_Role role) = 0;
|
|
virtual Renderable_Frame_View capture_frame_view() = 0;
|
|
virtual Render_State* state(Renderable_State_Role role) = 0;
|
|
virtual Render_State* render_state() = 0;
|
|
virtual Render_State* ready_state() = 0;
|
|
virtual Render_State* edit_state() = 0;
|
|
virtual Input_Data* input_data(Renderable_Input_Role role) = 0;
|
|
virtual Input_Data* render_input_data() = 0;
|
|
virtual Input_Data* edit_input_data() = 0;
|
|
virtual ~Render_Data() = default;
|
|
virtual void draw(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) {}
|
|
virtual void prepare_data(const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) {}
|
|
virtual Rect pixel_bounds(const Size& plot_size) {
|
|
return {0, 0, plot_size.width, plot_size.height};
|
|
}
|
|
[[nodiscard]] virtual bool requires_frame_view() const {
|
|
return false;
|
|
}
|
|
protected:
|
|
virtual void copy_render_state_object(Render_State& target, const Render_State& source) {
|
|
target.version = source.version;
|
|
}
|
|
};
|
|
|
|
struct Base_Render_Data : Render_Data {
|
|
void initialize_runtime(std::unique_ptr<Renderable_Runtime>) override {}
|
|
void cancel_pending_completions() override {}
|
|
void drain_committed_update_states(std::pmr::vector<std::shared_ptr<Update_State>>&) override {}
|
|
Render_State_Read_Guard acquire_state_read(Renderable_State_Role) override {
|
|
return {};
|
|
}
|
|
Render_State_Read_Guard acquire_render_state_read() override {
|
|
return {};
|
|
}
|
|
Render_State_Read_Guard acquire_edit_state_read() override {
|
|
return {};
|
|
}
|
|
Render_State_Write_Guard acquire_edit_state() override {
|
|
return {};
|
|
}
|
|
Render_Input_Write_Guard acquire_edit_input(bool) override {
|
|
return {};
|
|
}
|
|
Render_Input_Frame_Guard acquire_input_read(Renderable_Input_Role) override {
|
|
return {};
|
|
}
|
|
Render_State* state(Renderable_State_Role) override {
|
|
return nullptr;
|
|
}
|
|
Render_State* render_state() override {
|
|
return nullptr;
|
|
}
|
|
Render_State* ready_state() override {
|
|
return nullptr;
|
|
}
|
|
Render_State* edit_state() override {
|
|
return nullptr;
|
|
}
|
|
Input_Data* render_input_data() override {
|
|
return nullptr;
|
|
}
|
|
Input_Data* edit_input_data() override {
|
|
return nullptr;
|
|
}
|
|
Input_Data* input_data(Renderable_Input_Role) override {
|
|
return nullptr;
|
|
}
|
|
Renderable_Frame_View capture_frame_view() override {
|
|
return {};
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
concept Render_State_Type = std::derived_from<T, Render_State> && std::is_copy_assignable_v<T>;
|
|
|
|
template <typename T>
|
|
concept Input_Data_Type = std::derived_from<T, Input_Data>;
|
|
|
|
template <typename T>
|
|
concept Render_Data_Type = std::derived_from<T, Render_Data>;
|
|
|
|
} // namespace renderive
|