aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/facade
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/facade')
-rw-r--r--src/crepe/facade/CMakeLists.txt2
-rw-r--r--src/crepe/facade/SDLContext.cpp362
-rw-r--r--src/crepe/facade/SDLContext.h151
-rw-r--r--src/crepe/facade/SDLFontContext.cpp54
-rw-r--r--src/crepe/facade/SDLFontContext.h18
-rw-r--r--src/crepe/facade/font.cpp21
-rw-r--r--src/crepe/facade/font.h31
7 files changed, 535 insertions, 104 deletions
diff --git a/src/crepe/facade/CMakeLists.txt b/src/crepe/facade/CMakeLists.txt
index 4cc53bc..9b73323 100644
--- a/src/crepe/facade/CMakeLists.txt
+++ b/src/crepe/facade/CMakeLists.txt
@@ -3,6 +3,7 @@ target_sources(crepe PUBLIC
SoundContext.cpp
SDLContext.cpp
DB.cpp
+ SDLFontContext.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -10,5 +11,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
SoundContext.h
SDLContext.h
DB.h
+ SDLFontContext.h
)
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index 9f60285..6becf60 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -1,17 +1,21 @@
#include <SDL2/SDL.h>
+#include <SDL2/SDL_blendmode.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_surface.h>
#include <SDL2/SDL_video.h>
+#include <array>
#include <cmath>
#include <cstddef>
+#include <cstdint>
#include <functional>
#include <memory>
#include <stdexcept>
#include "../api/Camera.h"
+#include "../api/Color.h"
#include "../api/Config.h"
#include "../api/Sprite.h"
#include "../api/Texture.h"
@@ -72,32 +76,150 @@ SDLContext::~SDLContext() {
IMG_Quit();
SDL_Quit();
}
-void SDLContext::handle_events(bool & running) {
- //TODO: wouter i need events
- /*
- SDL_Event event;
- SDL_PollEvent(&event);
- switch (event.type) {
- case SDL_QUIT:
- running = false;
- break;
- case SDL_KEYDOWN:
- triggerEvent(KeyPressedEvent(getCustomKey(event.key.keysym.sym)));
- break;
- case SDL_MOUSEBUTTONDOWN:
- int x, y;
- SDL_GetMouseState(&x, &y);
- triggerEvent(MousePressedEvent(x, y));
- break;
+
+Keycode SDLContext::sdl_to_keycode(SDL_Keycode sdl_key) {
+ static const std::array<Keycode, SDL_NUM_SCANCODES> LOOKUP_TABLE = [] {
+ std::array<Keycode, SDL_NUM_SCANCODES> table{};
+ table.fill(Keycode::NONE);
+
+ table[SDL_SCANCODE_SPACE] = Keycode::SPACE;
+ table[SDL_SCANCODE_APOSTROPHE] = Keycode::APOSTROPHE;
+ table[SDL_SCANCODE_COMMA] = Keycode::COMMA;
+ table[SDL_SCANCODE_MINUS] = Keycode::MINUS;
+ table[SDL_SCANCODE_PERIOD] = Keycode::PERIOD;
+ table[SDL_SCANCODE_SLASH] = Keycode::SLASH;
+ table[SDL_SCANCODE_0] = Keycode::D0;
+ table[SDL_SCANCODE_1] = Keycode::D1;
+ table[SDL_SCANCODE_2] = Keycode::D2;
+ table[SDL_SCANCODE_3] = Keycode::D3;
+ table[SDL_SCANCODE_4] = Keycode::D4;
+ table[SDL_SCANCODE_5] = Keycode::D5;
+ table[SDL_SCANCODE_6] = Keycode::D6;
+ table[SDL_SCANCODE_7] = Keycode::D7;
+ table[SDL_SCANCODE_8] = Keycode::D8;
+ table[SDL_SCANCODE_9] = Keycode::D9;
+ table[SDL_SCANCODE_SEMICOLON] = Keycode::SEMICOLON;
+ table[SDL_SCANCODE_EQUALS] = Keycode::EQUAL;
+ table[SDL_SCANCODE_A] = Keycode::A;
+ table[SDL_SCANCODE_B] = Keycode::B;
+ table[SDL_SCANCODE_C] = Keycode::C;
+ table[SDL_SCANCODE_D] = Keycode::D;
+ table[SDL_SCANCODE_E] = Keycode::E;
+ table[SDL_SCANCODE_F] = Keycode::F;
+ table[SDL_SCANCODE_G] = Keycode::G;
+ table[SDL_SCANCODE_H] = Keycode::H;
+ table[SDL_SCANCODE_I] = Keycode::I;
+ table[SDL_SCANCODE_J] = Keycode::J;
+ table[SDL_SCANCODE_K] = Keycode::K;
+ table[SDL_SCANCODE_L] = Keycode::L;
+ table[SDL_SCANCODE_M] = Keycode::M;
+ table[SDL_SCANCODE_N] = Keycode::N;
+ table[SDL_SCANCODE_O] = Keycode::O;
+ table[SDL_SCANCODE_P] = Keycode::P;
+ table[SDL_SCANCODE_Q] = Keycode::Q;
+ table[SDL_SCANCODE_R] = Keycode::R;
+ table[SDL_SCANCODE_S] = Keycode::S;
+ table[SDL_SCANCODE_T] = Keycode::T;
+ table[SDL_SCANCODE_U] = Keycode::U;
+ table[SDL_SCANCODE_V] = Keycode::V;
+ table[SDL_SCANCODE_W] = Keycode::W;
+ table[SDL_SCANCODE_X] = Keycode::X;
+ table[SDL_SCANCODE_Y] = Keycode::Y;
+ table[SDL_SCANCODE_Z] = Keycode::Z;
+ table[SDL_SCANCODE_LEFTBRACKET] = Keycode::LEFT_BRACKET;
+ table[SDL_SCANCODE_BACKSLASH] = Keycode::BACKSLASH;
+ table[SDL_SCANCODE_RIGHTBRACKET] = Keycode::RIGHT_BRACKET;
+ table[SDL_SCANCODE_GRAVE] = Keycode::GRAVE_ACCENT;
+ table[SDL_SCANCODE_ESCAPE] = Keycode::ESCAPE;
+ table[SDL_SCANCODE_RETURN] = Keycode::ENTER;
+ table[SDL_SCANCODE_TAB] = Keycode::TAB;
+ table[SDL_SCANCODE_BACKSPACE] = Keycode::BACKSPACE;
+ table[SDL_SCANCODE_INSERT] = Keycode::INSERT;
+ table[SDL_SCANCODE_DELETE] = Keycode::DELETE;
+ table[SDL_SCANCODE_RIGHT] = Keycode::RIGHT;
+ table[SDL_SCANCODE_LEFT] = Keycode::LEFT;
+ table[SDL_SCANCODE_DOWN] = Keycode::DOWN;
+ table[SDL_SCANCODE_UP] = Keycode::UP;
+ table[SDL_SCANCODE_PAGEUP] = Keycode::PAGE_UP;
+ table[SDL_SCANCODE_PAGEDOWN] = Keycode::PAGE_DOWN;
+ table[SDL_SCANCODE_HOME] = Keycode::HOME;
+ table[SDL_SCANCODE_END] = Keycode::END;
+ table[SDL_SCANCODE_CAPSLOCK] = Keycode::CAPS_LOCK;
+ table[SDL_SCANCODE_SCROLLLOCK] = Keycode::SCROLL_LOCK;
+ table[SDL_SCANCODE_NUMLOCKCLEAR] = Keycode::NUM_LOCK;
+ table[SDL_SCANCODE_PRINTSCREEN] = Keycode::PRINT_SCREEN;
+ table[SDL_SCANCODE_PAUSE] = Keycode::PAUSE;
+ table[SDL_SCANCODE_F1] = Keycode::F1;
+ table[SDL_SCANCODE_F2] = Keycode::F2;
+ table[SDL_SCANCODE_F3] = Keycode::F3;
+ table[SDL_SCANCODE_F4] = Keycode::F4;
+ table[SDL_SCANCODE_F5] = Keycode::F5;
+ table[SDL_SCANCODE_F6] = Keycode::F6;
+ table[SDL_SCANCODE_F7] = Keycode::F7;
+ table[SDL_SCANCODE_F8] = Keycode::F8;
+ table[SDL_SCANCODE_F9] = Keycode::F9;
+ table[SDL_SCANCODE_F10] = Keycode::F10;
+ table[SDL_SCANCODE_F11] = Keycode::F11;
+ table[SDL_SCANCODE_F12] = Keycode::F12;
+ table[SDL_SCANCODE_KP_0] = Keycode::KP0;
+ table[SDL_SCANCODE_KP_1] = Keycode::KP1;
+ table[SDL_SCANCODE_KP_2] = Keycode::KP2;
+ table[SDL_SCANCODE_KP_3] = Keycode::KP3;
+ table[SDL_SCANCODE_KP_4] = Keycode::KP4;
+ table[SDL_SCANCODE_KP_5] = Keycode::KP5;
+ table[SDL_SCANCODE_KP_6] = Keycode::KP6;
+ table[SDL_SCANCODE_KP_7] = Keycode::KP7;
+ table[SDL_SCANCODE_KP_8] = Keycode::KP8;
+ table[SDL_SCANCODE_KP_9] = Keycode::KP9;
+ table[SDL_SCANCODE_LSHIFT] = Keycode::LEFT_SHIFT;
+ table[SDL_SCANCODE_LCTRL] = Keycode::LEFT_CONTROL;
+ table[SDL_SCANCODE_LALT] = Keycode::LEFT_ALT;
+ table[SDL_SCANCODE_LGUI] = Keycode::LEFT_SUPER;
+ table[SDL_SCANCODE_RSHIFT] = Keycode::RIGHT_SHIFT;
+ table[SDL_SCANCODE_RCTRL] = Keycode::RIGHT_CONTROL;
+ table[SDL_SCANCODE_RALT] = Keycode::RIGHT_ALT;
+ table[SDL_SCANCODE_RGUI] = Keycode::RIGHT_SUPER;
+ table[SDL_SCANCODE_MENU] = Keycode::MENU;
+
+ return table;
+ }();
+
+ if (sdl_key < 0 || sdl_key >= SDL_NUM_SCANCODES) {
+ return Keycode::NONE;
}
- */
+
+ return LOOKUP_TABLE[sdl_key];
}
-void SDLContext::clear_screen() {
+MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) {
+ static const std::array<MouseButton, 5> MOUSE_BUTTON_LOOKUP_TABLE = [] {
+ std::array<MouseButton, 5> table{};
+ table.fill(MouseButton::NONE);
+
+ table[SDL_BUTTON_LEFT] = MouseButton::LEFT_MOUSE;
+ table[SDL_BUTTON_RIGHT] = MouseButton::RIGHT_MOUSE;
+ table[SDL_BUTTON_MIDDLE] = MouseButton::MIDDLE_MOUSE;
+ table[SDL_BUTTON_X1] = MouseButton::X1_MOUSE;
+ table[SDL_BUTTON_X2] = MouseButton::X2_MOUSE;
+
+ return table;
+ }();
+
+ if (sdl_button >= MOUSE_BUTTON_LOOKUP_TABLE.size()) {
+ // Return NONE for invalid or unmapped button
+ return MouseButton::NONE;
+ }
+
+ return MOUSE_BUTTON_LOOKUP_TABLE[sdl_button];
+}
+
+void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer.get()); }
+void SDLContext::present_screen() {
SDL_SetRenderDrawColor(this->game_renderer.get(), 0, 0, 0, 255);
- SDL_RenderClear(this->game_renderer.get());
+ SDL_RenderFillRectF(this->game_renderer.get(), &black_bars[0]);
+ SDL_RenderFillRectF(this->game_renderer.get(), &black_bars[1]);
+ SDL_RenderPresent(this->game_renderer.get());
}
-void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer.get()); }
SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const {
return SDL_Rect{
@@ -107,39 +229,62 @@ SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const {
.h = sprite.mask.h,
};
}
-SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const vec2 & pos, const Camera & cam,
- const vec2 & cam_pos, const double & img_scale) const {
- int width = sprite.height * sprite.aspect_ratio;
- int height = sprite.height;
+SDL_FRect SDLContext::get_dst_rect(const DestinationRectangleData & ctx) const {
- width *= img_scale * cam.zoom;
- height *= img_scale * cam.zoom;
+ const Sprite::Data & data = ctx.sprite.data;
- return SDL_Rect{
- .x = static_cast<int>((pos.x - cam_pos.x + (cam.viewport_size.x / 2) - width / 2)),
- .y = static_cast<int>((pos.y - cam_pos.y + (cam.viewport_size.y / 2) - height / 2)),
- .w = width,
- .h = height,
+ vec2 size = data.size;
+ if (data.size.x == 0 && data.size.y != 0) {
+ size.x = data.size.y * ctx.sprite.aspect_ratio;
+ }
+ if (data.size.y == 0 && data.size.x != 0) {
+ size.y = data.size.x / ctx.sprite.aspect_ratio;
+ }
+
+ const CameraValues & cam = ctx.cam;
+
+ size *= cam.render_scale * ctx.img_scale * data.scale_offset;
+
+ vec2 screen_pos
+ = (ctx.pos + data.position_offset - cam.cam_pos + (cam.zoomed_viewport) / 2)
+ * cam.render_scale
+ - size / 2 + cam.bar_size;
+
+ return SDL_FRect{
+ .x = screen_pos.x,
+ .y = screen_pos.y,
+ .w = size.x,
+ .h = size.y,
};
}
void SDLContext::draw(const RenderContext & ctx) {
+ const Sprite::Data & data = ctx.sprite.data;
SDL_RendererFlip render_flip
- = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * ctx.sprite.flip.flip_x)
- | (SDL_FLIP_VERTICAL * ctx.sprite.flip.flip_y));
+ = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * data.flip.flip_x)
+ | (SDL_FLIP_VERTICAL * data.flip.flip_y));
SDL_Rect srcrect = this->get_src_rect(ctx.sprite);
- SDL_Rect dstrect
- = this->get_dst_rect(ctx.sprite, ctx.pos, ctx.cam, ctx.cam_pos, ctx.scale);
-
- SDL_RenderCopyEx(this->game_renderer.get(), ctx.sprite.sprite_image.texture.get(),
- &srcrect, &dstrect, ctx.angle, NULL, render_flip);
+ SDL_FRect dstrect = this->get_dst_rect(SDLContext::DestinationRectangleData{
+ .sprite = ctx.sprite,
+ .cam = ctx.cam,
+ .pos = ctx.pos,
+ .img_scale = ctx.scale,
+ });
+
+ double angle = ctx.angle + data.angle_offset;
+
+ this->set_color_texture(ctx.sprite.texture, ctx.sprite.data.color);
+ SDL_RenderCopyExF(this->game_renderer.get(), ctx.sprite.texture.texture.get(), &srcrect,
+ &dstrect, angle, NULL, render_flip);
}
-void SDLContext::set_camera(const Camera & cam) {
+SDLContext::CameraValues SDLContext::set_camera(const Camera & cam) {
+ const Camera::Data & cam_data = cam.data;
+ CameraValues ret_cam;
// resize window
int w, h;
SDL_GetWindowSize(this->game_window.get(), &w, &h);
@@ -147,42 +292,52 @@ void SDLContext::set_camera(const Camera & cam) {
SDL_SetWindowSize(this->game_window.get(), cam.screen.x, cam.screen.y);
}
- double screen_aspect = cam.screen.x / cam.screen.y;
- double viewport_aspect = cam.viewport_size.x / cam.viewport_size.y;
+ vec2 & zoomed_viewport = ret_cam.zoomed_viewport;
+ vec2 & bar_size = ret_cam.bar_size;
+ vec2 & render_scale = ret_cam.render_scale;
+
+ zoomed_viewport = cam.viewport_size * cam_data.zoom;
+ float screen_aspect = static_cast<float>(cam.screen.x) / cam.screen.y;
+ float viewport_aspect = zoomed_viewport.x / zoomed_viewport.y;
- SDL_Rect view;
// calculate black bars
if (screen_aspect > viewport_aspect) {
- // letterboxing
- view.h = cam.screen.y / cam.zoom;
- view.w = cam.screen.y * viewport_aspect;
- view.x = (cam.screen.x - view.w) / 2;
- view.y = 0;
- } else {
// pillarboxing
- view.h = cam.screen.x / viewport_aspect;
- view.w = cam.screen.x / cam.zoom;
- view.x = 0;
- view.y = (cam.screen.y - view.h) / 2;
+ float scale = cam.screen.y / zoomed_viewport.y;
+ float adj_width = zoomed_viewport.x * scale;
+ float bar_width = (cam.screen.x - adj_width) / 2;
+ this->black_bars[0] = {0, 0, bar_width, (float) cam.screen.y};
+ this->black_bars[1] = {(cam.screen.x - bar_width), 0, bar_width, (float) cam.screen.y};
+
+ bar_size = {bar_width, 0};
+ render_scale.x = render_scale.y = scale;
+ } else {
+ // letterboxing
+ float scale = cam.screen.x / (cam.viewport_size.x * cam_data.zoom);
+ float adj_height = cam.viewport_size.y * scale;
+ float bar_height = (cam.screen.y - adj_height) / 2;
+ this->black_bars[0] = {0, 0, (float) cam.screen.x, bar_height};
+ this->black_bars[1]
+ = {0, (cam.screen.y - bar_height), (float) cam.screen.x, bar_height};
+
+ bar_size = {0, bar_height};
+ render_scale.x = render_scale.y = scale;
}
- // set drawing area
- SDL_RenderSetViewport(this->game_renderer.get(), &view);
-
- SDL_RenderSetLogicalSize(this->game_renderer.get(), static_cast<int>(cam.viewport_size.x),
- static_cast<int>(cam.viewport_size.y));
- // set bg color
- SDL_SetRenderDrawColor(this->game_renderer.get(), cam.bg_color.r, cam.bg_color.g,
- cam.bg_color.b, cam.bg_color.a);
+ SDL_SetRenderDrawColor(this->game_renderer.get(), cam_data.bg_color.r, cam_data.bg_color.g,
+ cam_data.bg_color.b, cam_data.bg_color.a);
SDL_Rect bg = {
.x = 0,
.y = 0,
- .w = static_cast<int>(cam.viewport_size.x),
- .h = static_cast<int>(cam.viewport_size.y),
+ .w = cam.screen.x,
+ .h = cam.screen.y,
};
+
// fill bg color
SDL_RenderFillRect(this->game_renderer.get(), &bg);
+
+ return ret_cam;
}
uint64_t SDLContext::get_ticks() const { return SDL_GetTicks64(); }
@@ -207,16 +362,79 @@ SDLContext::texture_from_path(const std::string & path) {
std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>> img_texture;
img_texture = {tmp_texture, [](SDL_Texture * texture) { SDL_DestroyTexture(texture); }};
+ SDL_SetTextureBlendMode(img_texture.get(), SDL_BLENDMODE_BLEND);
return img_texture;
}
-int SDLContext::get_width(const Texture & ctx) const {
- int w;
- SDL_QueryTexture(ctx.texture.get(), NULL, NULL, &w, NULL);
- return w;
-}
-int SDLContext::get_height(const Texture & ctx) const {
- int h;
- SDL_QueryTexture(ctx.texture.get(), NULL, NULL, NULL, &h);
- return h;
+
+ivec2 SDLContext::get_size(const Texture & ctx) {
+ ivec2 size;
+ SDL_QueryTexture(ctx.texture.get(), NULL, NULL, &size.x, &size.y);
+ return size;
}
+
void SDLContext::delay(int ms) const { SDL_Delay(ms); }
+
+std::vector<SDLContext::EventData> SDLContext::get_events() {
+ std::vector<SDLContext::EventData> event_list;
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_QUIT:
+ event_list.push_back(EventData{
+ .event_type = SDLContext::EventType::SHUTDOWN,
+ });
+ break;
+ case SDL_KEYDOWN:
+ event_list.push_back(EventData{
+ .event_type = SDLContext::EventType::KEYDOWN,
+ .key = sdl_to_keycode(event.key.keysym.scancode),
+ .key_repeat = (event.key.repeat != 0),
+ });
+ break;
+ case SDL_KEYUP:
+ event_list.push_back(EventData{
+ .event_type = SDLContext::EventType::KEYUP,
+ .key = sdl_to_keycode(event.key.keysym.scancode),
+ });
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ event_list.push_back(EventData{
+ .event_type = SDLContext::EventType::MOUSEDOWN,
+ .mouse_button = sdl_to_mousebutton(event.button.button),
+ .mouse_position = {event.button.x, event.button.y},
+ });
+ break;
+ case SDL_MOUSEBUTTONUP: {
+ int x, y;
+ SDL_GetMouseState(&x, &y);
+ event_list.push_back(EventData{
+ .event_type = SDLContext::EventType::MOUSEUP,
+ .mouse_button = sdl_to_mousebutton(event.button.button),
+ .mouse_position = {event.button.x, event.button.y},
+ });
+ } break;
+
+ case SDL_MOUSEMOTION: {
+ event_list.push_back(
+ EventData{.event_type = SDLContext::EventType::MOUSEMOVE,
+ .mouse_position = {event.motion.x, event.motion.y},
+ .rel_mouse_move = {event.motion.xrel, event.motion.yrel}});
+ } break;
+
+ case SDL_MOUSEWHEEL: {
+ event_list.push_back(EventData{
+ .event_type = SDLContext::EventType::MOUSEWHEEL,
+ .mouse_position = {event.motion.x, event.motion.y},
+ // TODO: why is this needed?
+ .scroll_direction = event.wheel.y < 0 ? -1 : 1,
+ .scroll_delta = event.wheel.preciseY,
+ });
+ } break;
+ }
+ }
+ return event_list;
+}
+void SDLContext::set_color_texture(const Texture & texture, const Color & color) {
+ SDL_SetTextureColorMod(texture.texture.get(), color.r, color.g, color.b);
+ SDL_SetTextureAlphaMod(texture.texture.get(), color.a);
+}
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index 6030a6e..e232511 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -1,5 +1,6 @@
#pragma once
+#include <SDL2/SDL.h>
#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
@@ -9,36 +10,88 @@
#include <memory>
#include <string>
-#include "../api/Camera.h"
-#include "../api/Sprite.h"
-
+#include "api/Camera.h"
+#include "api/Color.h"
+#include "api/KeyCodes.h"
+#include "api/Sprite.h"
+#include "api/Texture.h"
+#include "api/Transform.h"
#include "types.h"
namespace crepe {
-// TODO: SDL_Keycode is defined in a header not distributed with crepe, which means this
-// typedef is unusable when crepe is packaged. Wouter will fix this later.
-typedef SDL_Keycode CREPE_KEYCODES;
-
+class LoopManager;
+class InputSystem;
/**
* \class SDLContext
* \brief Facade for the SDL library
- *
+ *
* SDLContext is a singleton that handles the SDL window and renderer, provides methods for
* event handling, and rendering to the screen. It is never used directly by the user
*/
class SDLContext {
public:
+ //! data that the camera component cannot hold
+ struct CameraValues {
+
+ //! zoomed in viewport in game_units
+ vec2 zoomed_viewport;
+
+ /**
+ * \brief scaling factor
+ *
+ * depending on the black bars type will the scaling be different.
+ * - letterboxing --> scaling on the y-as
+ * - pillarboxing --> scaling on the x-as
+ */
+ vec2 render_scale;
+
+ /**
+ * \brief size of calculated black bars
+ *
+ * depending on the black bars type will the size be different
+ * - lettorboxing --> {0, bar_height}
+ * - pillarboxing --> {bar_width , 0}
+ */
+ vec2 bar_size;
+
+ //! Calculated camera position
+ vec2 cam_pos;
+ };
+
+ //! rendering data needed to render on screen
struct RenderContext {
const Sprite & sprite;
- const Camera & cam;
- const vec2 & cam_pos;
+ const CameraValues & cam;
const vec2 & pos;
const double & angle;
const double & scale;
};
public:
+ //! EventType enum for passing eventType
+ enum EventType {
+ NONE = 0,
+ MOUSEDOWN,
+ MOUSEUP,
+ MOUSEMOVE,
+ MOUSEWHEEL,
+ KEYUP,
+ KEYDOWN,
+ SHUTDOWN,
+
+ };
+ //! EventData struct for passing event data from facade
+ struct EventData {
+ SDLContext::EventType event_type = SDLContext::EventType::NONE;
+ Keycode key = Keycode::NONE;
+ bool key_repeat = false;
+ MouseButton mouse_button = MouseButton::NONE;
+ ivec2 mouse_position = {-1, -1};
+ int scroll_direction = -1;
+ float scroll_delta = INFINITY;
+ ivec2 rel_mouse_move = {-1, -1};
+ };
/**
* \brief Gets the singleton instance of SDLContext.
* \return Reference to the SDLContext instance.
@@ -51,17 +104,42 @@ public:
SDLContext & operator=(SDLContext &&) = delete;
private:
- //! will only use handle_events
- friend class LoopManager;
+ //! will only use get_events
+ friend class InputSystem;
+ /**
+ * \brief Retrieves a list of all events from the SDL context.
+ *
+ * This method retrieves all the events from the SDL context that are currently
+ * available. It is primarily used by the InputSystem to process various
+ * input events such as mouse clicks, mouse movements, and keyboard presses.
+ *
+ * \return Events that occurred since last call to `get_events()`
+ */
+ std::vector<SDLContext::EventData> get_events();
+
+ /**
+ * \brief Converts an SDL key code to the custom Keycode type.
+ *
+ * This method maps an SDL key code to the corresponding `Keycode` enum value,
+ * which is used internally by the system to identify the keys.
+ *
+ * \param sdl_key The SDL key code to convert.
+ * \return The corresponding `Keycode` value or `Keycode::NONE` if the key is unrecognized.
+ */
+ Keycode sdl_to_keycode(SDL_Keycode sdl_key);
+
/**
- * \brief Handles SDL events such as window close and input.
- * \param running Reference to a boolean flag that controls the main loop.
+ * \brief Converts an SDL mouse button code to the custom MouseButton type.
+ *
+ * This method maps an SDL mouse button code to the corresponding `MouseButton`
+ * enum value, which is used internally by the system to identify mouse buttons.
+ *
+ * \param sdl_button The SDL mouse button code to convert.
+ * \return The corresponding `MouseButton` value or `MouseButton::NONE` if the key is unrecognized
*/
- void handle_events(bool & running);
+ MouseButton sdl_to_mousebutton(Uint8 sdl_button);
private:
- //! Will only use get_ticks
- friend class AnimatorSystem;
//! Will only use delay
friend class LoopTimer;
/**
@@ -104,18 +182,11 @@ private:
std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>>
texture_from_path(const std::string & path);
/**
- * \brief Gets the width of a texture.
+ * \brief Gets the size of a texture.
* \param texture Reference to the Texture object.
- * \return Width of the texture as an integer.
+ * \return Width and height of the texture as an integer.
*/
- int get_width(const Texture & texture) const;
-
- /**
- * \brief Gets the height of a texture.
- * \param texture Reference to the Texture object.
- * \return Height of the texture as an integer.
- */
- int get_height(const Texture & texture) const;
+ ivec2 get_size(const Texture & ctx);
private:
//! Will use draw,clear_screen, present_screen, camera.
@@ -123,7 +194,7 @@ private:
/**
* \brief Draws a sprite to the screen using the specified transform and camera.
- * \param RenderCtx Reference to rendering data to draw
+ * \param RenderContext Reference to rendering data to draw
*/
void draw(const RenderContext & ctx);
@@ -137,9 +208,16 @@ private:
* \brief sets the background of the camera (will be adjusted in future PR)
* \param camera Reference to the Camera object.
*/
- void set_camera(const Camera & camera);
+ CameraValues set_camera(const Camera & camera);
private:
+ //! the data needed to construct a sdl dst rectangle
+ struct DestinationRectangleData {
+ const Sprite & sprite;
+ const CameraValues & cam;
+ const vec2 & pos;
+ const double & img_scale;
+ };
/**
* \brief calculates the sqaure size of the image
*
@@ -155,11 +233,17 @@ private:
* \param pos the pos in world units
* \param cam the camera of the current scene
* \param cam_pos the current postion of the camera
- * \param img_scale the image multiplier for increasing img size
+ * \param img_scale the image multiplier for increasing img size
* \return sdl rectangle to draw a dst image to draw on the screen
*/
- SDL_Rect get_dst_rect(const Sprite & sprite, const vec2 & pos, const Camera & cam,
- const vec2 & cam_pos, const double & img_scale) const;
+ SDL_FRect get_dst_rect(const DestinationRectangleData & data) const;
+ /**
+ * \brief Set an additional color value multiplied into render copy operations.
+ *
+ * \param texture the given texture to adjust
+ * \param color the color data for the texture
+ */
+ void set_color_texture(const Texture & texture, const Color & color);
private:
//! sdl Window
@@ -167,6 +251,9 @@ private:
//! renderer for the crepe engine
std::unique_ptr<SDL_Renderer, std::function<void(SDL_Renderer *)>> game_renderer;
+
+ //! black bars rectangle to draw
+ SDL_FRect black_bars[2] = {};
};
} // namespace crepe
diff --git a/src/crepe/facade/SDLFontContext.cpp b/src/crepe/facade/SDLFontContext.cpp
new file mode 100644
index 0000000..a4be143
--- /dev/null
+++ b/src/crepe/facade/SDLFontContext.cpp
@@ -0,0 +1,54 @@
+#include <stdexcept>
+
+#include "SDLFontContext.h"
+
+
+using namespace crepe;
+using namespace std;
+
+SDLFontContext::SDLFontContext(){
+
+}
+
+SDLFontContext::~SDLFontContext(){
+
+}
+unique_ptr<Asset> SDLFontContext::get_font_asset(const std::string & font_family) {
+ if (!FcInit()) {
+ throw std::runtime_error("Failed to initialize Fontconfig.");
+ }
+ // Create a pattern to search for the font family
+ FcPattern* pattern = FcNameParse(reinterpret_cast<const FcChar8*>(font_family.c_str()));
+ if (!pattern) {
+ throw std::runtime_error("Failed to create font pattern.");
+ }
+
+ // Default configuration
+ FcConfig* config = FcConfigGetCurrent();
+ if (!config) {
+ FcPatternDestroy(pattern);
+ throw std::runtime_error("Failed to get current Fontconfig configuration.");
+ }
+
+ // Match the font pattern
+ FcResult result;
+ FcPattern* matched_pattern = FcFontMatch(config, pattern, &result);
+ FcPatternDestroy(pattern);
+
+ if (!matched_pattern) {
+ throw std::runtime_error("No matching font found.");
+ }
+
+ // Extract the file path
+ FcChar8* file_path = nullptr;
+ if (FcPatternGetString(matched_pattern, FC_FILE, 0, &file_path) != FcResultMatch || !file_path) {
+ FcPatternDestroy(matched_pattern);
+ throw std::runtime_error("Failed to get font file path.");
+ }
+
+ // Convert the file path to a std::string
+ std::string font_file_path(reinterpret_cast<const char*>(file_path));
+ FcPatternDestroy(matched_pattern);
+ FcFini();
+ return std::move(make_unique<Asset>(font_file_path));
+}
diff --git a/src/crepe/facade/SDLFontContext.h b/src/crepe/facade/SDLFontContext.h
new file mode 100644
index 0000000..cd91383
--- /dev/null
+++ b/src/crepe/facade/SDLFontContext.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <memory>
+#include <SDL2/SDL_ttf.h>
+#include <fontconfig/fontconfig.h>
+
+#include "../api/Asset.h"
+
+namespace crepe {
+ class SDLFontContext{
+ public:
+ SDLFontContext();
+ ~SDLFontContext();
+ std::unique_ptr<Asset> get_font_asset(const std::string & font_family);
+ private:
+ };
+
+}
diff --git a/src/crepe/facade/font.cpp b/src/crepe/facade/font.cpp
new file mode 100644
index 0000000..259a6cd
--- /dev/null
+++ b/src/crepe/facade/font.cpp
@@ -0,0 +1,21 @@
+#include "font.h"
+#include "../api/Config.h"
+using namespace std;
+using namespace crepe;
+
+void Font::load(unique_ptr<Asset> res){
+ const char* font_path = res->get_path();
+ int font_size = Config::get_instance().font.font_size;
+ this->font = std::unique_ptr<TTF_Font, decltype(&TTF_CloseFont)>(
+ TTF_OpenFont(font_path, font_size), &TTF_CloseFont);
+
+ if (!font) {
+ throw std::runtime_error("Failed to load font: " + std::string(TTF_GetError()));
+ }
+}
+Font::Font(const char* src){
+ this->load(make_unique<Asset>(src));
+}
+Font::Font(std::unique_ptr<Asset> res){
+ this->load(std::move(res));
+}
diff --git a/src/crepe/facade/font.h b/src/crepe/facade/font.h
new file mode 100644
index 0000000..a8d8040
--- /dev/null
+++ b/src/crepe/facade/font.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <memory>
+#include <SDL2/SDL_ttf.h>
+
+#include "../api/Asset.h"
+
+namespace crepe {
+
+/**
+ * \brief Font resource facade
+ *
+ * This class is a wrapper around an SDL_ttf font instance, encapsulating font loading and usage.
+ */
+class Font : public Resource{
+public:
+ /**
+ * \param res A unique pointer to an Asset holding the font resource.
+ */
+ Font(const Asset & src, Mediator & mediator);
+
+ /**
+ * \brief Destructor to clean up font resources.
+ */
+ ~Font() = default;
+private:
+ //! The SDL_ttf font object with custom deleter.
+ std::unique_ptr<TTF_Font, decltype(&TTF_CloseFont)> font;
+};
+
+} // namespace crepe