165 lines
6.7 KiB
C++
165 lines
6.7 KiB
C++
#pragma once
|
|
#include <concepts>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include "Renderable_Core.h"
|
|
namespace YSG {
|
|
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>;
|
|
template <Render_Data_Type Base, typename Owner, Render_State_Type State, Input_Data_Type Input>
|
|
struct Typed_Render_Data_Base : Base {
|
|
Owner* q() {
|
|
return reinterpret_cast<Owner*>(this->qPtr);
|
|
}
|
|
State* render_state() override {
|
|
return reinterpret_cast<State*>(this->state(State_Render));
|
|
}
|
|
State* ready_state() override {
|
|
return reinterpret_cast<State*>(this->state(State_Ready));
|
|
}
|
|
State* edit_state() override {
|
|
return reinterpret_cast<State*>(this->state(State_Edit));
|
|
}
|
|
Input* render_input_data() override {
|
|
return reinterpret_cast<Input*>(this->input_data(Input_Render));
|
|
}
|
|
Input* edit_input_data() override {
|
|
return reinterpret_cast<Input*>(this->input_data(Input_Edit));
|
|
}
|
|
State* state_data(SRC src) {
|
|
return reinterpret_cast<State*>(this->state(src));
|
|
}
|
|
State* state_data_by_index(std::uint8_t index) {
|
|
return reinterpret_cast<State*>(this->state_by_index(index));
|
|
}
|
|
Input* input_data_by_index(std::uint8_t index) {
|
|
return reinterpret_cast<Input*>(Base::input_data_by_index(index));
|
|
}
|
|
template <typename Field>
|
|
Field state_value(Field State::* field, SRC src) {
|
|
return state_data(src)->*field;
|
|
}
|
|
template <typename Field>
|
|
void set_state_value(Field State::* field, Field value) {
|
|
auto lease = this->mStateControl.wait_mark_use_role(State_Edit);
|
|
auto state = state_data_by_index(lease.index);
|
|
Render_Edit_Guard guard(this, lease);
|
|
state->*field = std::move(value);
|
|
}
|
|
void sync_state_pipeline() override {
|
|
Triple_Buffer_Lease editLease = this->mStateControl.wait_mark_use_role(State_Edit);
|
|
Triple_Buffer_Lease readyLease = this->mStateControl.wait_mark_use_role(State_Ready);
|
|
auto ready = reinterpret_cast<State*>(this->state_by_index(readyLease.index));
|
|
auto edit = reinterpret_cast<State*>(this->state_by_index(editLease.index));
|
|
if (buffer_version_newer(edit->version, ready->version))
|
|
*ready = *edit;
|
|
this->mStateControl.unmark_use(readyLease);
|
|
this->mStateControl.unmark_use(editLease);
|
|
this->mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) {
|
|
auto ready = reinterpret_cast<State*>(this->state_by_index(view[State_Ready]));
|
|
auto render = reinterpret_cast<State*>(this->state_by_index(view[State_Render]));
|
|
return buffer_version_newer(ready->version, render->version);
|
|
});
|
|
this->mInputControl.wait_swap_role(Input_Edit, Input_Ready, [this](const Triple_Buffer_View& view) {
|
|
const Input_Buffer_Slot& edit = this->input_slot_by_index(view[Input_Edit]);
|
|
const Input_Buffer_Slot& ready = this->input_slot_by_index(view[Input_Ready]);
|
|
return edit.pending && buffer_version_newer(edit.version, ready.version);
|
|
});
|
|
this->mInputControl.wait_swap_role(Input_Ready, Input_Render, [this](const Triple_Buffer_View& view) {
|
|
const Input_Buffer_Slot& ready = this->input_slot_by_index(view[Input_Ready]);
|
|
const Input_Buffer_Slot& render = this->input_slot_by_index(view[Input_Render]);
|
|
return ready.pending && buffer_version_newer(ready.version, render.version);
|
|
});
|
|
if (!this->mRenderStart)
|
|
this->mRenderStart = true;
|
|
}
|
|
};
|
|
template <typename Owner, Render_State_Type State, Input_Data_Type Input>
|
|
using Typed_Render_Data = Typed_Render_Data_Base<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->dPtr = new Data;
|
|
owner->mObjectName = name;
|
|
}
|
|
static Data* d(Owner* owner) {
|
|
return reinterpret_cast<Data*>(owner->dPtr);
|
|
}
|
|
static Render_Data* create_render_data() {
|
|
return new Data;
|
|
}
|
|
static Render_State* create_render_state() {
|
|
return new State;
|
|
}
|
|
static Input_Data* create_input_data() {
|
|
return new Input;
|
|
}
|
|
};
|
|
template <Render_Data_Type Data, Render_State_Type State>
|
|
struct Render_State_Lease {
|
|
explicit Render_State_Lease(Data* data) : data(data), lease(data->mStateControl.wait_mark_use_role(State_Edit)), state(reinterpret_cast<State*>(data->state_by_index(lease.index))) {
|
|
}
|
|
Render_State_Lease(const Render_State_Lease&) = delete;
|
|
Render_State_Lease& operator=(const Render_State_Lease&) = delete;
|
|
~Render_State_Lease() {
|
|
data->unmark_state(lease);
|
|
}
|
|
State* operator->() {
|
|
return state;
|
|
}
|
|
State& operator*() {
|
|
return *state;
|
|
}
|
|
Data* data{};
|
|
Triple_Buffer_Lease lease{};
|
|
State* state{};
|
|
};
|
|
template <Render_Data_Type Data, Render_State_Type State>
|
|
struct Render_Edit_Lease {
|
|
explicit Render_Edit_Lease(Data* data) : data(data), lease(data->mStateControl.wait_mark_use_role(State_Edit)), state(reinterpret_cast<State*>(data->state_by_index(lease.index))) {
|
|
}
|
|
Render_Edit_Lease(const Render_Edit_Lease&) = delete;
|
|
Render_Edit_Lease& operator=(const Render_Edit_Lease&) = delete;
|
|
~Render_Edit_Lease() {
|
|
++data->state_by_index(lease.index)->version;
|
|
if (data->qPtr)
|
|
data->qPtr->mark_render_dirty();
|
|
data->unmark_state(lease);
|
|
}
|
|
State* operator->() {
|
|
return state;
|
|
}
|
|
State& operator*() {
|
|
return *state;
|
|
}
|
|
Data* data{};
|
|
Triple_Buffer_Lease lease{};
|
|
State* state{};
|
|
};
|
|
template <Render_Data_Type Data, Input_Data_Type Input>
|
|
struct Render_Input_Lease {
|
|
explicit Render_Input_Lease(Data* data, bool notify_render = true) : data(data), notify_render(notify_render), lease(data->mInputControl.wait_mark_use_role(Input_Edit)), input(reinterpret_cast<Input*>(data->input_data_by_index(lease.index))) {
|
|
}
|
|
Render_Input_Lease(const Render_Input_Lease&) = delete;
|
|
Render_Input_Lease& operator=(const Render_Input_Lease&) = delete;
|
|
~Render_Input_Lease() {
|
|
data->mark_input_dirty(lease, notify_render);
|
|
data->mInputControl.unmark_use(lease);
|
|
}
|
|
Input* operator->() {
|
|
return input;
|
|
}
|
|
Input& operator*() {
|
|
return *input;
|
|
}
|
|
Data* data{};
|
|
bool notify_render{};
|
|
Triple_Buffer_Lease lease{};
|
|
Input* input{};
|
|
};
|
|
} // namespace YSG
|