2023-07-31 07:27:01 +00:00
|
|
|
#include "screen.h"
|
|
|
|
|
2023-07-31 11:39:46 +00:00
|
|
|
// standard library includes
|
|
|
|
#include <cassert>
|
|
|
|
#ifndef NDEBUG
|
|
|
|
#include <iostream>
|
|
|
|
#endif // NDEBUG
|
|
|
|
|
2023-08-23 08:35:24 +00:00
|
|
|
// third party includes
|
|
|
|
#include <raylib.h>
|
|
|
|
|
2023-07-31 11:39:46 +00:00
|
|
|
// local includes
|
|
|
|
#include "screen_test.h"
|
|
|
|
|
2023-07-31 07:27:01 +00:00
|
|
|
Screen::Screen(std::weak_ptr<ScreenStack> stack) : stack(stack) {}
|
|
|
|
|
2023-07-31 11:39:46 +00:00
|
|
|
ScreenStack::PendingAction::PendingAction() : screen(), action(Action::NOP) {}
|
|
|
|
|
|
|
|
ScreenStack::PendingAction::PendingAction(Action action)
|
2023-08-17 07:07:09 +00:00
|
|
|
: screen(), action(action) {
|
|
|
|
switch (action) {
|
|
|
|
case Action::PUSH_SCREEN:
|
|
|
|
case Action::CONSTRUCT_SCREEN:
|
|
|
|
// Cannot push non-existant screen.
|
|
|
|
this->action = Action::NOP;
|
|
|
|
#ifndef NDEBUG
|
|
|
|
std::clog << "WARNING: Cannot create PendingAction with PUSH_SCREEN or "
|
|
|
|
"CONSTRUCT_SCREEN!\n";
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-07-31 11:39:46 +00:00
|
|
|
|
|
|
|
ScreenStack::PendingAction::PendingAction(Screen::Ptr &&screen)
|
|
|
|
: screen(std::forward<Screen::Ptr>(screen)), action(Action::PUSH_SCREEN) {}
|
|
|
|
|
2023-08-17 03:58:52 +00:00
|
|
|
ScreenStack::PendingAction::PendingAction(
|
|
|
|
std::function<Screen::Ptr(ScreenStack::Weak)> &&fn)
|
|
|
|
: screen(std::forward<std::function<Screen::Ptr(ScreenStack::Weak)> >(fn)),
|
|
|
|
action(Action::CONSTRUCT_SCREEN) {}
|
|
|
|
|
2023-07-31 07:27:01 +00:00
|
|
|
ScreenStack::Ptr ScreenStack::new_instance() {
|
|
|
|
std::shared_ptr<ScreenStack> ptr =
|
|
|
|
std::shared_ptr<ScreenStack>(new ScreenStack{});
|
|
|
|
ptr->self_weak = ptr;
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2023-08-23 07:37:26 +00:00
|
|
|
ScreenStack::~ScreenStack() {
|
|
|
|
UnloadRenderTexture(*render_texture);
|
|
|
|
render_texture.reset();
|
|
|
|
}
|
|
|
|
|
2023-07-31 07:27:01 +00:00
|
|
|
void ScreenStack::update(float dt) {
|
2023-07-31 11:39:46 +00:00
|
|
|
handle_pending_actions();
|
|
|
|
|
2023-08-23 07:37:26 +00:00
|
|
|
bool resized = IsWindowResized();
|
|
|
|
if (resized) {
|
|
|
|
reset_render_texture();
|
|
|
|
}
|
|
|
|
|
2023-07-31 07:27:01 +00:00
|
|
|
auto idx = stack.size();
|
2023-07-31 11:39:46 +00:00
|
|
|
if (idx == 0) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
std::cerr << "WARNING: Stack is empty, pushing TestScreen...\n";
|
|
|
|
#endif // NDEBUG
|
|
|
|
push_screen(Screen::new_screen<TestScreen>(self_weak));
|
|
|
|
update(dt);
|
|
|
|
return;
|
|
|
|
}
|
2023-08-23 07:37:26 +00:00
|
|
|
while (idx > 0 && stack.at(--idx)->update(dt, resized)) {
|
2023-07-31 07:27:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScreenStack::draw() {
|
2023-08-23 06:16:41 +00:00
|
|
|
for (decltype(stack.size()) idx = 0;
|
2023-08-23 07:37:26 +00:00
|
|
|
idx < stack.size() && stack.at(idx)->draw(render_texture.get()); ++idx) {
|
2023-07-31 07:27:01 +00:00
|
|
|
}
|
2023-08-23 07:37:26 +00:00
|
|
|
|
|
|
|
BeginDrawing();
|
|
|
|
DrawTextureRec(
|
|
|
|
render_texture->texture,
|
|
|
|
Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
|
|
|
|
{0, 0}, WHITE);
|
|
|
|
EndDrawing();
|
2023-07-31 07:27:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScreenStack::push_screen(Screen::Ptr &&screen) {
|
2023-07-31 11:39:46 +00:00
|
|
|
actions.push_back(PendingAction(std::forward<Screen::Ptr>(screen)));
|
2023-07-31 07:27:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScreenStack::pop_screen() {
|
2023-07-31 11:39:46 +00:00
|
|
|
actions.push_back(PendingAction(Action::POP_SCREEN));
|
2023-07-31 07:27:01 +00:00
|
|
|
}
|
|
|
|
|
2023-08-01 08:55:30 +00:00
|
|
|
void ScreenStack::clear_screens() {
|
|
|
|
actions.push_back(PendingAction(Action::CLEAR_SCREENS));
|
|
|
|
}
|
|
|
|
|
2023-08-23 07:37:26 +00:00
|
|
|
void ScreenStack::reset_render_texture() {
|
|
|
|
UnloadRenderTexture(*render_texture);
|
|
|
|
|
|
|
|
*render_texture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
|
|
|
}
|
|
|
|
|
|
|
|
ScreenStack::ScreenStack()
|
|
|
|
: render_texture(new RenderTexture), self_weak(), stack(), actions() {
|
|
|
|
*render_texture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
|
|
|
}
|
2023-07-31 11:39:46 +00:00
|
|
|
|
|
|
|
void ScreenStack::handle_pending_actions() {
|
|
|
|
while (!actions.empty()) {
|
|
|
|
switch (actions.front().action) {
|
|
|
|
case Action::PUSH_SCREEN:
|
2023-08-17 03:58:52 +00:00
|
|
|
stack.emplace_back(
|
|
|
|
std::move(std::get<Screen::Ptr>(actions.front().screen)));
|
2023-07-31 11:39:46 +00:00
|
|
|
break;
|
|
|
|
case Action::POP_SCREEN:
|
|
|
|
if (!stack.empty()) {
|
|
|
|
stack.pop_back();
|
|
|
|
}
|
2023-07-31 11:45:16 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
else {
|
|
|
|
std::cerr << "WARNING: Tried to pop screen when stack was empty!\n";
|
|
|
|
}
|
|
|
|
#endif // NDEBUG
|
2023-07-31 11:39:46 +00:00
|
|
|
break;
|
2023-08-01 08:55:30 +00:00
|
|
|
case Action::CLEAR_SCREENS:
|
|
|
|
#ifndef NDEBUG
|
|
|
|
if (stack.empty()) {
|
|
|
|
std::cerr << "WARNING: Clearing an empty screen stack!\n";
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
stack.clear();
|
|
|
|
break;
|
2023-08-17 03:58:52 +00:00
|
|
|
case Action::CONSTRUCT_SCREEN:
|
|
|
|
stack.emplace_back(
|
|
|
|
std::get<std::function<Screen::Ptr(ScreenStack::Weak)> >(
|
|
|
|
actions.front().screen)(self_weak));
|
|
|
|
break;
|
2023-07-31 11:39:46 +00:00
|
|
|
case Action::NOP:
|
|
|
|
// Intentionally left blank.
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(!"unreachable");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
actions.pop_front();
|
|
|
|
}
|
|
|
|
}
|