192 lines
6.7 KiB
C++
192 lines
6.7 KiB
C++
#pragma once
|
|
#include "Renderable.h"
|
|
#include "Strategy_Render_Data.h"
|
|
#include <utility>
|
|
|
|
namespace renderive {
|
|
|
|
template <typename Base, typename Owner, Render_State_Type State, Input_Data_Type Input>
|
|
requires std::derived_from<Base, Render_Data>
|
|
struct Typed_Render_Data_Base : Base {
|
|
Owner* q() {
|
|
return reinterpret_cast<Owner*>(this->q_ptr);
|
|
}
|
|
State* render_state() override {
|
|
return reinterpret_cast<State*>(this->state(Renderable_State_Role::Render));
|
|
}
|
|
State* ready_state() override {
|
|
return reinterpret_cast<State*>(this->state(Renderable_State_Role::Ready));
|
|
}
|
|
State* edit_state() override {
|
|
return reinterpret_cast<State*>(this->state(Renderable_State_Role::Edit));
|
|
}
|
|
Input* render_input_data() override {
|
|
return reinterpret_cast<Input*>(this->input_data(Renderable_Input_Role::Render));
|
|
}
|
|
Input* edit_input_data() override {
|
|
return reinterpret_cast<Input*>(this->input_data(Renderable_Input_Role::Edit));
|
|
}
|
|
State* render_state(const Renderable_Frame_View& frame_view) const {
|
|
return reinterpret_cast<State*>(frame_view.state);
|
|
}
|
|
Input* render_input_data(const Renderable_Frame_View& frame_view) const {
|
|
return reinterpret_cast<Input*>(frame_view.input);
|
|
}
|
|
State* state_data(Renderable_State_Role role) {
|
|
return reinterpret_cast<State*>(this->state(role));
|
|
}
|
|
template <typename Field, typename Source_State>
|
|
requires std::derived_from<State, Source_State>
|
|
Field state_value(Field Source_State::* field, Renderable_State_Role role) {
|
|
auto guard = this->acquire_state_read(role);
|
|
if (!guard)
|
|
return {};
|
|
auto state = reinterpret_cast<State*>(guard.state);
|
|
return state->*field;
|
|
}
|
|
template <typename Field, typename Source_State>
|
|
requires std::derived_from<State, Source_State>
|
|
Field edit_state_value(Field Source_State::* field) {
|
|
return state_value(field, Renderable_State_Role::Edit);
|
|
}
|
|
template <typename Field, typename Source_State>
|
|
requires std::derived_from<State, Source_State>
|
|
Field ready_state_value(Field Source_State::* field) {
|
|
return state_value(field, Renderable_State_Role::Ready);
|
|
}
|
|
template <typename Field, typename Source_State>
|
|
requires std::derived_from<State, Source_State>
|
|
Field render_state_value(Field Source_State::* field) {
|
|
return state_value(field, Renderable_State_Role::Render);
|
|
}
|
|
template <typename Field, typename Source_State>
|
|
requires std::derived_from<State, Source_State>
|
|
void set_state_value(Field Source_State::* field, Field value) {
|
|
auto guard = this->acquire_edit_state();
|
|
if (!guard)
|
|
return;
|
|
auto state = reinterpret_cast<State*>(guard.state);
|
|
state->*field = std::move(value);
|
|
}
|
|
protected:
|
|
void copy_render_state_object(Render_State& target, const Render_State& source) override {
|
|
static_cast<State&>(target) = static_cast<const State&>(source);
|
|
}
|
|
};
|
|
|
|
template <typename Owner, Render_State_Type State, Input_Data_Type Input>
|
|
using Typed_Render_Data = Typed_Render_Data_Base<Strategy_Render_Data, Owner, State, Input>;
|
|
|
|
template <typename Owner, Render_Data_Type Data, Render_State_Type State, Input_Data_Type Input>
|
|
struct Renderable_Binding {
|
|
static void init(Owner* owner, const char* name) {
|
|
owner->d_owner = make_render_object<Data>();
|
|
owner->d_ptr = static_cast<Render_Data*>(owner->d_owner.template get<Data>());
|
|
owner->set_object_name(name);
|
|
}
|
|
static Data* d(Owner* owner) {
|
|
return reinterpret_cast<Data*>(owner->d_ptr);
|
|
}
|
|
static Render_Object_Owner create_render_data() {
|
|
return make_render_object<Data>();
|
|
}
|
|
static Render_Object_Owner create_render_state() {
|
|
return make_render_object<State>();
|
|
}
|
|
static Render_Object_Owner create_input_data() {
|
|
if constexpr (std::is_same_v<Input, Input_Data>)
|
|
return {};
|
|
return make_render_object<Input>();
|
|
}
|
|
};
|
|
|
|
#define RENDERIVE_DEFINE_RENDERABLE_BINDING(Owner, Data, State, Input, Name) \
|
|
using Owner##_Binding = ::renderive::Renderable_Binding<Owner, Data, State, Input>; \
|
|
Owner::Owner() { \
|
|
Owner##_Binding::init(this, Name); \
|
|
} \
|
|
Data* Owner::d() { \
|
|
return Owner##_Binding::d(this); \
|
|
} \
|
|
::renderive::Render_Object_Owner Owner::create_render_data() { \
|
|
return Owner##_Binding::create_render_data(); \
|
|
} \
|
|
::renderive::Render_Object_Owner Owner::create_render_state() { \
|
|
return Owner##_Binding::create_render_state(); \
|
|
} \
|
|
::renderive::Render_Object_Owner Owner::create_input_data() { \
|
|
return Owner##_Binding::create_input_data(); \
|
|
}
|
|
|
|
template <typename Data, Render_State_Type State>
|
|
requires std::derived_from<Data, Render_Data>
|
|
struct Render_State_Lease : Immovable {
|
|
explicit Render_State_Lease(Data* data) : data(data) {
|
|
guard = data->acquire_edit_state_read();
|
|
state = reinterpret_cast<State*>(guard.state);
|
|
}
|
|
~Render_State_Lease() = default;
|
|
State* operator->() {
|
|
return state;
|
|
}
|
|
State& operator*() {
|
|
return *state;
|
|
}
|
|
explicit operator bool() const {
|
|
return state && guard;
|
|
}
|
|
Data* data{};
|
|
Render_State_Read_Guard guard;
|
|
State* state{};
|
|
};
|
|
|
|
template <typename Data, Render_State_Type State>
|
|
requires std::derived_from<Data, Render_Data>
|
|
struct Render_Edit_Lease : Immovable {
|
|
explicit Render_Edit_Lease(Data* data) : data(data) {
|
|
guard = data->acquire_edit_state();
|
|
state = reinterpret_cast<State*>(guard.state);
|
|
}
|
|
~Render_Edit_Lease() = default;
|
|
State* operator->() {
|
|
return state;
|
|
}
|
|
State& operator*() {
|
|
return *state;
|
|
}
|
|
explicit operator bool() const {
|
|
return state && guard;
|
|
}
|
|
Data* data{};
|
|
Render_State_Write_Guard guard;
|
|
State* state{};
|
|
};
|
|
|
|
template <typename Data, Input_Data_Type Input>
|
|
requires std::derived_from<Data, Render_Data>
|
|
struct Render_Input_Lease : Immovable {
|
|
explicit Render_Input_Lease(Data* data, bool notify_render = true) : data(data), notify_render(notify_render) {
|
|
guard = data->acquire_edit_input(notify_render);
|
|
input = reinterpret_cast<Input*>(guard.input);
|
|
}
|
|
~Render_Input_Lease() = default;
|
|
Input* operator->() {
|
|
return input;
|
|
}
|
|
Input& operator*() {
|
|
return *input;
|
|
}
|
|
explicit operator bool() const {
|
|
return input && guard;
|
|
}
|
|
void set_completion(std::shared_ptr<Update_State> state) {
|
|
guard.set_completion(std::move(state));
|
|
}
|
|
Data* data{};
|
|
bool notify_render{};
|
|
Render_Input_Write_Guard guard;
|
|
Input* input{};
|
|
};
|
|
|
|
} // namespace renderive
|