aboutsummaryrefslogtreecommitdiff
path: root/src/crepe
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-11-12 15:11:51 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-11-12 15:11:51 +0100
commit33454c2c8d8c0abdfd405608af4e6cd53a25e7c4 (patch)
treeef5131afc629815e993775423602a6e8af5fcb5f /src/crepe
parent067247360d68042ad5466b802399338c14d7dc58 (diff)
parent656df6ddd6b5231705798540c347efeebf8ac8a9 (diff)
merge `master` into `loek/cleanup`
Diffstat (limited to 'src/crepe')
-rw-r--r--src/crepe/Exception.cpp1
-rw-r--r--src/crepe/ValueBroker.hpp3
-rw-r--r--src/crepe/api/Animator.cpp23
-rw-r--r--src/crepe/api/Animator.h76
-rw-r--r--src/crepe/api/CMakeLists.txt4
-rw-r--r--src/crepe/api/Camera.cpp17
-rw-r--r--src/crepe/api/Camera.h55
-rw-r--r--src/crepe/api/Color.cpp3
-rw-r--r--src/crepe/api/Color.h17
-rw-r--r--src/crepe/api/Sprite.cpp7
-rw-r--r--src/crepe/api/Sprite.h76
-rw-r--r--src/crepe/api/Texture.cpp15
-rw-r--r--src/crepe/api/Texture.h54
-rw-r--r--src/crepe/api/Transform.h2
-rw-r--r--src/crepe/facade/DB.cpp1
-rw-r--r--src/crepe/facade/SDLContext.cpp200
-rw-r--r--src/crepe/facade/SDLContext.h118
-rw-r--r--src/crepe/system/AnimatorSystem.cpp37
-rw-r--r--src/crepe/system/AnimatorSystem.h44
-rw-r--r--src/crepe/system/CMakeLists.txt2
-rw-r--r--src/crepe/system/RenderSystem.cpp36
-rw-r--r--src/crepe/system/RenderSystem.h49
22 files changed, 708 insertions, 132 deletions
diff --git a/src/crepe/Exception.cpp b/src/crepe/Exception.cpp
index bfdbcdd..a1fa765 100644
--- a/src/crepe/Exception.cpp
+++ b/src/crepe/Exception.cpp
@@ -14,3 +14,4 @@ Exception::Exception(const char * fmt, ...) {
this->error = va_stringf(args, fmt);
va_end(args);
}
+
diff --git a/src/crepe/ValueBroker.hpp b/src/crepe/ValueBroker.hpp
index 5c3bed9..927142f 100644
--- a/src/crepe/ValueBroker.hpp
+++ b/src/crepe/ValueBroker.hpp
@@ -6,8 +6,7 @@ namespace crepe {
template <typename T>
ValueBroker<T>::ValueBroker(const setter_t & setter, const getter_t & getter)
- : setter(setter),
- getter(getter) {}
+ : setter(setter), getter(getter) {}
template <typename T>
const T & ValueBroker<T>::get() {
diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp
new file mode 100644
index 0000000..8b396af
--- /dev/null
+++ b/src/crepe/api/Animator.cpp
@@ -0,0 +1,23 @@
+
+#include <cstdint>
+
+#include "util/log.h"
+
+#include "Animator.h"
+#include "Component.h"
+#include "Sprite.h"
+
+using namespace crepe;
+
+Animator::Animator(uint32_t id, Sprite & ss, int row, int col, int col_animator)
+ : Component(id), spritesheet(ss), row(row), col(col) {
+ dbg_trace();
+
+ animator_rect = spritesheet.sprite_rect;
+ animator_rect.h /= col;
+ animator_rect.w /= row;
+ animator_rect.x = 0;
+ animator_rect.y = col_animator * animator_rect.h;
+ this->active = false;
+}
+Animator::~Animator() { dbg_trace(); }
diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h
new file mode 100644
index 0000000..def0240
--- /dev/null
+++ b/src/crepe/api/Animator.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <cstdint>
+
+#include "Component.h"
+#include "Sprite.h"
+
+namespace crepe {
+class AnimatorSystem;
+class SDLContext;
+
+/**
+ * \brief The Animator component is used to animate sprites by managing the movement
+ * and frame changes within a sprite sheet.
+ *
+ * This component allows for controlling sprite animation through rows and columns of a sprite sheet.
+ * It can be used to play animations, loop them, or stop them.
+ */
+class Animator : public Component {
+
+public:
+ //TODO: need to implement this
+ void loop();
+ void stop();
+
+public:
+ /**
+ * \brief Constructs an Animator object that will control animations for a sprite sheet.
+ *
+ * \param id The unique identifier for the component, typically assigned automatically.
+ * \param spritesheet A reference to the Sprite object which holds the sprite sheet for animation.
+ * \param row The maximum number of rows in the sprite sheet.
+ * \param col The maximum number of columns in the sprite sheet.
+ * \param col__animate The specific col index of the sprite sheet to animate. This allows selecting which col to animate from multiple col in the sheet.
+ *
+ * This constructor sets up the Animator with the given parameters, and initializes the animation system.
+ */
+ Animator(uint32_t id, Sprite & spritesheet, int row, int col,
+ int col_animate);
+
+ ~Animator(); // dbg_trace
+ Animator(const Animator &) = delete;
+ Animator(Animator &&) = delete;
+ Animator & operator=(const Animator &) = delete;
+ Animator & operator=(Animator &&) = delete;
+
+private:
+ //! A reference to the Sprite sheet containing the animation frames.
+ Sprite & spritesheet;
+
+ //! The maximum number of columns in the sprite sheet.
+ const int col;
+
+ //! The maximum number of rows in the sprite sheet.
+ const int row;
+
+ //! The current col being animated.
+ int curr_col = 0;
+
+ //! The current row being animated.
+ int curr_row = 0;
+
+ Rect animator_rect;
+
+ //TODO: Is this necessary?
+ //int fps;
+
+private:
+ //! AnimatorSystem adjust the private member parameters of Animator;
+ friend class AnimatorSystem;
+
+ //! SDLContext reads the Animator member var's
+ friend class SDLContext;
+};
+} // namespace crepe
+//
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index 3b20142..87cbb09 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -16,6 +16,8 @@ target_sources(crepe PUBLIC
Scene.cpp
SceneManager.cpp
Vector2.cpp
+ Camera.cpp
+ Animator.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -38,4 +40,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Metadata.h
SceneManager.h
SceneManager.hpp
+ Camera.h
+ Animator.h
)
diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp
new file mode 100644
index 0000000..820a6a8
--- /dev/null
+++ b/src/crepe/api/Camera.cpp
@@ -0,0 +1,17 @@
+
+#include <cstdint>
+
+#include "util/log.h"
+
+#include "Camera.h"
+#include "Color.h"
+#include "Component.h"
+
+using namespace crepe;
+
+Camera::Camera(uint32_t id, const Color & bg_color)
+ : Component(id), bg_color(bg_color) {
+ dbg_trace();
+}
+
+Camera::~Camera() { dbg_trace(); }
diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h
new file mode 100644
index 0000000..ba3a9ef
--- /dev/null
+++ b/src/crepe/api/Camera.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <cstdint>
+
+#include "Color.h"
+#include "Component.h"
+
+namespace crepe {
+
+/**
+ * \class Camera
+ * \brief Represents a camera component for rendering in the game.
+ *
+ * The Camera class defines the view parameters, including background color,
+ * aspect ratio, position, and zoom level. It controls what part of the game
+ * world is visible on the screen.
+ */
+class Camera : public Component {
+
+public:
+ /**
+ * \brief Constructs a Camera with the specified ID and background color.
+ * \param id Unique identifier for the camera component.
+ * \param bg_color Background color for the camera view.
+ */
+ Camera(uint32_t id, const Color & bg_color);
+ ~Camera(); // dbg_trace only
+
+public:
+ //! Background color of the camera view.
+ Color bg_color;
+
+ //! Aspect ratio height for the camera.
+ double aspect_height = 480;
+
+ //! Aspect ratio width for the camera.
+ double aspect_width = 640;
+
+ //! X-coordinate of the camera position.
+ double x = 0.0;
+
+ //! Y-coordinate of the camera position.
+ double y = 0.0;
+
+ //! Zoom level of the camera view.
+ double zoom = 1.0;
+
+public:
+ /**
+ * \brief Gets the maximum number of camera instances allowed.
+ * \return Maximum instance count as an integer.
+ */
+ virtual int get_instances_max() const { return 10; }
+};
+} // namespace crepe
diff --git a/src/crepe/api/Color.cpp b/src/crepe/api/Color.cpp
index fc6313d..9e5f187 100644
--- a/src/crepe/api/Color.cpp
+++ b/src/crepe/api/Color.cpp
@@ -11,8 +11,7 @@ Color Color::cyan = Color(0, 255, 255, 0);
Color Color::yellow = Color(255, 255, 0, 0);
Color Color::magenta = Color(255, 0, 255, 0);
-// FIXME: do we really need double precision for color values?
-Color::Color(double red, double green, double blue, double alpha) {
+Color::Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
this->a = alpha;
this->r = red;
this->g = green;
diff --git a/src/crepe/api/Color.h b/src/crepe/api/Color.h
index 6b54888..aa47bf4 100644
--- a/src/crepe/api/Color.h
+++ b/src/crepe/api/Color.h
@@ -1,14 +1,17 @@
#pragma once
+#include <cstdint>
+
namespace crepe {
+// TODO: make Color a struct w/o constructors/destructors
class Color {
// FIXME: can't these colors be defined as a `static constexpr const Color`
// instead?
public:
- Color(double red, double green, double blue, double alpha);
+ Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha);
static const Color & get_white();
static const Color & get_red();
static const Color & get_green();
@@ -19,10 +22,11 @@ public:
static const Color & get_black();
private:
- double r;
- double g;
- double b;
- double a;
+ // TODO: why are these private!?
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
static Color white;
static Color red;
@@ -32,6 +36,9 @@ private:
static Color magenta;
static Color yellow;
static Color black;
+
+private:
+ friend class SDLContext;
};
} // namespace crepe
diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp
index 88a442b..6f0433f 100644
--- a/src/crepe/api/Sprite.cpp
+++ b/src/crepe/api/Sprite.cpp
@@ -1,7 +1,7 @@
-#include <cstdint>
#include <memory>
#include "../util/log.h"
+#include "facade/SDLContext.h"
#include "Component.h"
#include "Sprite.h"
@@ -10,13 +10,16 @@
using namespace std;
using namespace crepe;
-Sprite::Sprite(game_object_id_t id, shared_ptr<Texture> image,
+Sprite::Sprite(game_object_id_t id, const shared_ptr<Texture> image,
const Color & color, const FlipSettings & flip)
: Component(id),
color(color),
flip(flip),
sprite_image(image) {
dbg_trace();
+
+ this->sprite_rect.w = sprite_image->get_width();
+ this->sprite_rect.h = sprite_image->get_height();
}
Sprite::~Sprite() { dbg_trace(); }
diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h
index 00dcb27..deb3f93 100644
--- a/src/crepe/api/Sprite.h
+++ b/src/crepe/api/Sprite.h
@@ -1,32 +1,88 @@
#pragma once
-#include <SDL2/SDL_rect.h>
#include <cstdint>
#include <memory>
-#include "api/Color.h"
-#include "api/Texture.h"
-
+#include "Color.h"
#include "Component.h"
+#include "Texture.h"
namespace crepe {
+struct Rect {
+ int w = 0;
+ int h = 0;
+ int x = 0;
+ int y = 0;
+};
+
struct FlipSettings {
- bool flip_x = true;
- bool flip_y = true;
+ bool flip_x = false;
+ bool flip_y = false;
};
+class SDLContext;
+class Animator;
+class AnimatorSystem;
+
+/**
+ * \brief Represents a renderable sprite component.
+ *
+ * A renderable sprite that can be displayed in the game. It includes a texture,
+ * color, and flip settings, and is managed in layers with defined sorting orders.
+ */
class Sprite : public Component {
public:
- Sprite(game_object_id_t id, std::shared_ptr<Texture> image,
+ // TODO: Loek comment in github #27 will be looked another time
+ // about shared_ptr Texture
+ /**
+ * \brief Constructs a Sprite with specified parameters.
+ * \param game_id Unique identifier for the game object this sprite belongs to.
+ * \param image Shared pointer to the texture for this sprite.
+ * \param color Color tint applied to the sprite.
+ * \param flip Flip settings for horizontal and vertical orientation.
+ */
+ Sprite(game_object_id_t id, const std::shared_ptr<Texture> image,
const Color & color, const FlipSettings & flip);
+
+ /**
+ * \brief Destroys the Sprite instance.
+ */
~Sprite();
- std::shared_ptr<Texture> sprite_image;
+
+ //! Texture used for the sprite
+ const std::shared_ptr<Texture> sprite_image;
+ //! Color tint of the sprite
Color color;
+ //! Flip settings for the sprite
FlipSettings flip;
- uint8_t sorting_in_layer;
- uint8_t order_in_layer;
+ //! Layer sorting level of the sprite
+ uint8_t sorting_in_layer = 0;
+ //! Order within the sorting layer
+ uint8_t order_in_layer = 0;
+
+public:
+ /**
+ * \brief Gets the maximum number of instances allowed for this sprite.
+ * \return Maximum instance count as an integer.
+ *
+ * For now is this number randomly picked. I think it will eventually be 1.
+ */
+ virtual int get_instances_max() const { return 10; }
+
+private:
+ //! Reads the sprite_rect of sprite
+ friend class SDLContext;
+
+ //! Reads the all the variables plus the sprite_rect
+ friend class Animator;
+
+ //! Reads the all the variables plus the sprite_rect
+ friend class AnimatorSystem;
+
+ //! Render area of the sprite this will also be adjusted by the AnimatorSystem if an Animator object is present in GameObject
+ Rect sprite_rect;
};
} // namespace crepe
diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp
index 8fc5c13..5ebd23d 100644
--- a/src/crepe/api/Texture.cpp
+++ b/src/crepe/api/Texture.cpp
@@ -21,12 +21,19 @@ Texture::Texture(const char * src) {
Texture::~Texture() {
dbg_trace();
- if (this->texture != nullptr) {
- SDL_DestroyTexture(this->texture);
- }
+ this->texture.reset();
}
void Texture::load(unique_ptr<Asset> res) {
SDLContext & ctx = SDLContext::get_instance();
- this->texture = ctx.texture_from_path(res->canonical());
+ this->texture = std::move(ctx.texture_from_path(res->canonical()));
+}
+
+int Texture::get_width() const {
+ if (this->texture == nullptr) return 0;
+ return SDLContext::get_instance().get_width(*this);
+}
+int Texture::get_height() const {
+ if (this->texture == nullptr) return 0;
+ return SDLContext::get_instance().get_width(*this);
}
diff --git a/src/crepe/api/Texture.h b/src/crepe/api/Texture.h
index 9a86f6f..b89bc17 100644
--- a/src/crepe/api/Texture.h
+++ b/src/crepe/api/Texture.h
@@ -3,31 +3,75 @@
// FIXME: this header can't be included because this is an API header, and SDL2
// development headers won't be bundled with crepe. Why is this facade in the
// API namespace?
+
#include <SDL2/SDL_render.h>
+#include <functional>
#include <memory>
#include "Asset.h"
namespace crepe {
-class SDLContext;
-}
-namespace crepe {
+class SDLContext;
+class Animator;
+/**
+ * \class Texture
+ * \brief Manages texture loading and properties.
+ *
+ * The Texture class is responsible for loading an image from a source
+ * and providing access to its dimensions. Textures can be used for rendering.
+ */
class Texture {
public:
+ /**
+ * \brief Constructs a Texture from a file path.
+ * \param src Path to the image file to be loaded as a texture.
+ */
Texture(const char * src);
+
+ /**
+ * \brief Constructs a Texture from an Asset resource.
+ * \param res Unique pointer to an Asset resource containing texture data.
+ */
Texture(std::unique_ptr<Asset> res);
+
+ /**
+ * \brief Destroys the Texture instance, freeing associated resources.
+ */
~Texture();
+ // FIXME: this constructor shouldn't be necessary because this class doesn't
+ // manage memory
+
+ /**
+ * \brief Gets the width of the texture.
+ * \return Width of the texture in pixels.
+ */
+ int get_width() const;
+
+ /**
+ * \brief Gets the height of the texture.
+ * \return Height of the texture in pixels.
+ */
+ int get_height() const;
private:
+ /**
+ * \brief Loads the texture from an Asset resource.
+ * \param res Unique pointer to an Asset resource to load the texture from.
+ */
void load(std::unique_ptr<Asset> res);
private:
- SDL_Texture * texture = nullptr;
+ //! The texture of the class from the library
+ std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>> texture;
+
+ //! Grants SDLContext access to private members.
+ friend class SDLContext;
- friend class crepe::SDLContext;
+ //! Grants Animator access to private members.
+ friend class Animator;
};
} // namespace crepe
diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h
index d7a5b8a..756e45b 100644
--- a/src/crepe/api/Transform.h
+++ b/src/crepe/api/Transform.h
@@ -32,7 +32,7 @@ public:
public:
//! Translation (shift)
Vector2 position;
- //! Rotation, in radians
+ //! Rotation, in degrees
double rotation;
//! Multiplication factor
double scale;
diff --git a/src/crepe/facade/DB.cpp b/src/crepe/facade/DB.cpp
index 405f7c4..0805a08 100644
--- a/src/crepe/facade/DB.cpp
+++ b/src/crepe/facade/DB.cpp
@@ -63,3 +63,4 @@ bool DB::has(const std::string & key) noexcept {
}
return true;
}
+
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index 8da93e9..c4c96e2 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -1,16 +1,22 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
+#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_surface.h>
#include <SDL2/SDL_video.h>
#include <cmath>
#include <cstddef>
+#include <functional>
#include <iostream>
+#include <memory>
+#include <string>
+#include <utility>
#include "../api/Sprite.h"
#include "../api/Texture.h"
#include "../api/Transform.h"
#include "../util/log.h"
+#include "Exception.h"
#include "SDLContext.h"
@@ -21,34 +27,6 @@ SDLContext & SDLContext::get_instance() {
return instance;
}
-void SDLContext::handle_events(bool & running) {
- SDL_Event event;
- while (SDL_PollEvent(&event)) {
- if (event.type == SDL_QUIT) {
- running = false;
- }
- }
-}
-
-SDLContext::~SDLContext() {
- dbg_trace();
-
- if (this->game_renderer != nullptr)
- SDL_DestroyRenderer(this->game_renderer);
-
- if (this->game_window != nullptr) {
- SDL_DestroyWindow(this->game_window);
- }
-
- // TODO: how are we going to ensure that these are called from the same
- // thread that SDL_Init() was called on? This has caused problems for me
- // before.
- IMG_Quit();
- SDL_Quit();
-}
-
-void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer); }
-
SDLContext::SDLContext() {
dbg_trace();
// FIXME: read window defaults from config manager
@@ -59,26 +37,32 @@ SDLContext::SDLContext() {
<< std::endl;
return;
}
-
- this->game_window = SDL_CreateWindow(
+ SDL_Window * tmp_window = SDL_CreateWindow(
"Crepe Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
- 1920, 1080, SDL_WINDOW_SHOWN);
- if (!this->game_window) {
+ this->viewport.w, this->viewport.h, 0);
+ if (!tmp_window) {
// FIXME: throw exception
std::cerr << "Window could not be created! SDL_Error: "
<< SDL_GetError() << std::endl;
+ return;
}
+ this->game_window
+ = {tmp_window, [](SDL_Window * window) { SDL_DestroyWindow(window); }};
- this->game_renderer
- = SDL_CreateRenderer(this->game_window, -1, SDL_RENDERER_ACCELERATED);
- if (!this->game_renderer) {
+ SDL_Renderer * tmp_renderer = SDL_CreateRenderer(
+ this->game_window.get(), -1, SDL_RENDERER_ACCELERATED);
+ if (!tmp_renderer) {
// FIXME: throw exception
std::cerr << "Renderer could not be created! SDL_Error: "
<< SDL_GetError() << std::endl;
- SDL_DestroyWindow(this->game_window);
+ SDL_DestroyWindow(this->game_window.get());
return;
}
+ this->game_renderer = {tmp_renderer, [](SDL_Renderer * renderer) {
+ SDL_DestroyRenderer(renderer);
+ }};
+
int img_flags = IMG_INIT_PNG;
if (!(IMG_Init(img_flags) & img_flags)) {
// FIXME: throw exception
@@ -87,71 +71,123 @@ SDLContext::SDLContext() {
}
}
-void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer); }
+SDLContext::~SDLContext() {
+ dbg_trace();
-void SDLContext::draw(const Sprite & sprite, const Transform & transform) {
+ this->game_renderer.reset();
+ this->game_window.reset();
- static SDL_RendererFlip render_flip
+ // TODO: how are we going to ensure that these are called from the same
+ // thread that SDL_Init() was called on? This has caused problems for me
+ // before.
+ 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;
+ }
+ */
+}
+
+void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer.get()); }
+void SDLContext::present_screen() {
+ SDL_RenderPresent(this->game_renderer.get());
+}
+
+void SDLContext::draw(const Sprite & sprite, const Transform & transform,
+ const Camera & cam) {
+
+ SDL_RendererFlip render_flip
= (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x)
| (SDL_FLIP_VERTICAL * sprite.flip.flip_y));
- int w, h;
- SDL_QueryTexture(sprite.sprite_image->texture, NULL, NULL, &w, &h);
- // needs maybe camera for position
+ double adjusted_x = (transform.position.x - cam.x) * cam.zoom;
+ double adjusted_y = (transform.position.y - cam.y) * cam.zoom;
+ double adjusted_w = sprite.sprite_rect.w * transform.scale * cam.zoom;
+ double adjusted_h = sprite.sprite_rect.h * transform.scale * cam.zoom;
+
+ SDL_Rect srcrect = {
+ .x = sprite.sprite_rect.x,
+ .y = sprite.sprite_rect.y,
+ .w = sprite.sprite_rect.w,
+ .h = sprite.sprite_rect.h,
+ };
+
SDL_Rect dstrect = {
- .x = static_cast<int>(transform.position.x),
- .y = static_cast<int>(transform.position.y),
- .w = static_cast<int>(w * transform.scale),
- .h = static_cast<int>(h * transform.scale),
+ .x = static_cast<int>(adjusted_x),
+ .y = static_cast<int>(adjusted_y),
+ .w = static_cast<int>(adjusted_w),
+ .h = static_cast<int>(adjusted_h),
};
- double degrees = transform.rotation * 180 / M_PI;
- SDL_RenderCopyEx(this->game_renderer, sprite.sprite_image->texture, NULL,
- &dstrect, degrees, NULL, render_flip);
+ SDL_RenderCopyEx(this->game_renderer.get(),
+ sprite.sprite_image->texture.get(), &srcrect,
+
+ &dstrect, transform.rotation, NULL, render_flip);
}
-/*
-SDL_Texture * SDLContext::setTextureFromPath(const char * path, SDL_Rect & clip,
- const int row, const int col) {
- dbg_trace();
+void SDLContext::camera(const Camera & cam) {
+ this->viewport.w = static_cast<int>(cam.aspect_width);
+ this->viewport.h = static_cast<int>(cam.aspect_height);
+ this->viewport.x = static_cast<int>(cam.x) - (SCREEN_WIDTH / 2);
+ this->viewport.y = static_cast<int>(cam.y) - (SCREEN_HEIGHT / 2);
- SDL_Surface * tmp = IMG_Load(path);
- if (!tmp) {
- std::cerr << "Error surface " << IMG_GetError << std::endl;
- }
+ SDL_SetRenderDrawColor(this->game_renderer.get(), cam.bg_color.r,
+ cam.bg_color.g, cam.bg_color.b, cam.bg_color.a);
+}
- clip.
- w = tmp->w / col;
- clip.h = tmp->h / row;
+uint64_t SDLContext::get_ticks() const { return SDL_GetTicks64(); }
- SDL_Texture * CreatedTexture
- = SDL_CreateTextureFromSurface(this->game_renderer, tmp);
+std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>>
+SDLContext::texture_from_path(const std::string & path) {
- if (!CreatedTexture) {
- std::cerr << "Error could not create texture " << IMG_GetError
- << std::endl;
+ SDL_Surface * tmp = IMG_Load(path.c_str());
+ if (tmp == nullptr) {
+ throw Exception("surface cannot be load from %s", path.c_str());
}
- SDL_FreeSurface(tmp);
- return CreatedTexture;
-}
-*/
+ std::unique_ptr<SDL_Surface, std::function<void(SDL_Surface *)>>
+ img_surface;
+ img_surface
+ = {tmp, [](SDL_Surface * surface) { SDL_FreeSurface(surface); }};
-SDL_Texture * SDLContext::texture_from_path(const char * path) {
- dbg_trace();
+ SDL_Texture * tmp_texture = SDL_CreateTextureFromSurface(
+ this->game_renderer.get(), img_surface.get());
- SDL_Surface * tmp = IMG_Load(path);
- if (!tmp) {
- std::cerr << "Error surface " << IMG_GetError << std::endl;
+ if (tmp_texture == nullptr) {
+ throw Exception("Texture cannot be load from %s", path.c_str());
}
- SDL_Texture * created_texture
- = SDL_CreateTextureFromSurface(this->game_renderer, tmp);
- if (!created_texture) {
- std::cerr << "Error could not create texture " << IMG_GetError
- << std::endl;
- }
- SDL_FreeSurface(tmp);
+ std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>>
+ img_texture;
+ img_texture = {tmp_texture,
+ [](SDL_Texture * texture) { SDL_DestroyTexture(texture); }};
- return created_texture;
+ 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;
}
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index f1ba8a6..e358c21 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -1,48 +1,146 @@
#pragma once
+#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_video.h>
+#include <functional>
+#include <memory>
+#include <string>
#include "../api/Sprite.h"
#include "../api/Transform.h"
-#include "../system/RenderSystem.h"
+#include "api/Camera.h"
+
+// FIXME: this needs to be removed
+const int SCREEN_WIDTH = 640;
+const int SCREEN_HEIGHT = 480;
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 Texture;
+class LoopManager;
+
+/**
+ * \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:
- // singleton
+ /**
+ * \brief Gets the singleton instance of SDLContext.
+ * \return Reference to the SDLContext instance.
+ */
static SDLContext & get_instance();
+
SDLContext(const SDLContext &) = delete;
SDLContext(SDLContext &&) = delete;
SDLContext & operator=(const SDLContext &) = delete;
SDLContext & operator=(SDLContext &&) = delete;
- //TODO decide events wouter?
-
private:
+ //! will only use handle_events
+ friend class LoopManager;
+ /**
+ * \brief Handles SDL events such as window close and input.
+ * \param running Reference to a boolean flag that controls the main loop.
+ */
void handle_events(bool & running);
private:
+ //! Will only use get_ticks
+ friend class AnimatorSystem;
+
+ /**
+ * \brief Gets the current SDL ticks since the program started.
+ * \return Current ticks in milliseconds as a constant uint64_t.
+ */
+ uint64_t get_ticks() const;
+
+private:
+ /**
+ * \brief Constructs an SDLContext instance.
+ * Initializes SDL, creates a window and renderer.
+ */
SDLContext();
- virtual ~SDLContext();
+
+ /**
+ * \brief Destroys the SDLContext instance.
+ * Cleans up SDL resources, including the window and renderer.
+ */
+ ~SDLContext();
private:
+ //! Will use the funtions: texture_from_path, get_width,get_height.
friend class Texture;
- SDL_Texture * texture_from_path(const char *);
- //SDL_Texture* setTextureFromPath(const char*, SDL_Rect& clip, const int row, const int col);
+
+ //! Will use the funtions: texture_from_path, get_width,get_height.
+ friend class Animator;
+
+ /**
+ * \brief Loads a texture from a file path.
+ * \param path Path to the image file.
+ * \return Pointer to the created SDL_Texture.
+ */
+ std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>>
+ texture_from_path(const std::string & path);
+ /**
+ * \brief Gets the width of a texture.
+ * \param texture Reference to the Texture object.
+ * \return Width of the texture as an integer.
+ */
+ int get_width(const 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 &) const;
private:
+ //! Will use draw,clear_screen, present_screen, camera.
friend class RenderSystem;
- void draw(const Sprite &, const Transform &);
+
+ /**
+ * \brief Draws a sprite to the screen using the specified transform and camera.
+ * \param sprite Reference to the Sprite to draw.
+ * \param transform Reference to the Transform for positioning.
+ * \param camera Reference to the Camera for view adjustments.
+ */
+ void draw(const Sprite & sprite, const Transform & transform,
+ const Camera & camera);
+
+ //! Clears the screen, preparing for a new frame.
void clear_screen();
+
+ //! Presents the rendered frame to the screen.
void present_screen();
+ /**
+ * \brief Sets the current camera for rendering.
+ * \param camera Reference to the Camera object.
+ */
+ void camera(const Camera & camera);
+
private:
- SDL_Window * game_window = nullptr;
- SDL_Renderer * game_renderer = nullptr;
+ //! sdl Window
+ std::unique_ptr<SDL_Window, std::function<void(SDL_Window *)>> game_window;
+
+ //! renderer for the crepe engine
+ std::unique_ptr<SDL_Renderer, std::function<void(SDL_Renderer *)>>
+ game_renderer;
+
+ //! viewport for the camera window
+ SDL_Rect viewport = {0, 0, 640, 480};
};
} // namespace crepe
diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp
new file mode 100644
index 0000000..bf45362
--- /dev/null
+++ b/src/crepe/system/AnimatorSystem.cpp
@@ -0,0 +1,37 @@
+
+#include <cstdint>
+#include <functional>
+#include <vector>
+
+#include "api/Animator.h"
+#include "facade/SDLContext.h"
+#include "util/log.h"
+
+#include "AnimatorSystem.h"
+#include "ComponentManager.h"
+
+using namespace crepe;
+
+AnimatorSystem::AnimatorSystem() { dbg_trace(); }
+AnimatorSystem::~AnimatorSystem() { dbg_trace(); }
+
+AnimatorSystem & AnimatorSystem::get_instance() {
+ static AnimatorSystem instance;
+ return instance;
+}
+
+void AnimatorSystem::update() {
+ ComponentManager & mgr = ComponentManager::get_instance();
+
+ std::vector<std::reference_wrapper<Animator>> animations
+ = mgr.get_components_by_type<Animator>();
+
+ uint64_t tick = SDLContext::get_instance().get_ticks();
+ for (Animator & a : animations) {
+ if (a.active) {
+ a.curr_row = (tick / 100) % a.row;
+ a.animator_rect.x = (a.curr_row * a.animator_rect.w) + a.curr_col;
+ a.spritesheet.sprite_rect = a.animator_rect;
+ }
+ }
+}
diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h
new file mode 100644
index 0000000..969e9d1
--- /dev/null
+++ b/src/crepe/system/AnimatorSystem.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "System.h"
+
+//TODO:
+// control if flip works with animation system
+
+namespace crepe {
+
+/**
+ * \brief The AnimatorSystem is responsible for managing and updating all Animator components.
+ *
+ * This system is responsible for controlling the behavior of the animations for all entities
+ * that have the Animator component attached. It updates the animations by controlling their
+ * frame changes, looping behavior, and overall animation state.
+ */
+class AnimatorSystem : public System {
+
+public:
+ /**
+ * \brief Retrieves the singleton instance of the AnimatorSystem.
+ *
+ * \return A reference to the single instance of the AnimatorSystem.
+ *
+ * This method ensures that there is only one instance of the AnimatorSystem, following the
+ * singleton design pattern. It can be used to access the system globally.
+ */
+ static AnimatorSystem & get_instance();
+
+ /**
+ * \brief Updates the Animator components.
+ *
+ * This method is called periodically (likely every frame) to update the state of all
+ * Animator components, moving the animations forward and managing their behavior (e.g., looping).
+ */
+ void update() override;
+
+private:
+ // private because singleton
+ AnimatorSystem(); // dbg_trace
+ ~AnimatorSystem(); // dbg_trace
+};
+
+} // namespace crepe
diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt
index ff6f66f..4c18b87 100644
--- a/src/crepe/system/CMakeLists.txt
+++ b/src/crepe/system/CMakeLists.txt
@@ -4,6 +4,7 @@ target_sources(crepe PUBLIC
PhysicsSystem.cpp
CollisionSystem.cpp
RenderSystem.cpp
+ AnimatorSystem.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -12,4 +13,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
PhysicsSystem.h
CollisionSystem.h
RenderSystem.h
+ AnimatorSystem.h
)
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index 5a07cc2..10211a3 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -20,7 +20,25 @@ RenderSystem & RenderSystem::get_instance() {
return instance;
}
-void RenderSystem::update() {
+void RenderSystem::clear_screen() const {
+ SDLContext::get_instance().clear_screen();
+}
+
+void RenderSystem::present_screen() const {
+ SDLContext::get_instance().present_screen();
+}
+void RenderSystem::update_camera() {
+ ComponentManager & mgr = ComponentManager::get_instance();
+
+ std::vector<std::reference_wrapper<Camera>> cameras
+ = mgr.get_components_by_type<Camera>();
+
+ for (Camera & cam : cameras) {
+ SDLContext::get_instance().camera(cam);
+ this->curr_cam = &cam;
+ }
+}
+void RenderSystem::render_sprites() const {
ComponentManager & mgr = ComponentManager::get_instance();
@@ -28,14 +46,16 @@ void RenderSystem::update() {
= mgr.get_components_by_type<Sprite>();
SDLContext & render = SDLContext::get_instance();
- render.clear_screen();
-
for (const Sprite & sprite : sprites) {
- std::vector<std::reference_wrapper<Transform>> transforms
+ auto transforms
= mgr.get_components_by_id<Transform>(sprite.game_object_id);
- for (const Transform & transform : transforms) {
- render.draw(sprite, transform);
- }
+ render.draw(sprite, transforms[0], *curr_cam);
}
- render.present_screen();
+}
+
+void RenderSystem::update() {
+ this->clear_screen();
+ this->update_camera();
+ this->render_sprites();
+ this->present_screen();
}
diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h
index 4b910a4..70db21a 100644
--- a/src/crepe/system/RenderSystem.h
+++ b/src/crepe/system/RenderSystem.h
@@ -1,17 +1,64 @@
#pragma once
+#include "api/Camera.h"
+
#include "System.h"
namespace crepe {
+/**
+ * \class RenderSystem
+ * \brief Manages rendering operations for all game objects.
+ *
+ * RenderSystem is responsible for rendering sprites, clearing and presenting the screen,
+ * and managing the active camera. It functions as a singleton, providing centralized
+ * rendering services for the application.
+ */
class RenderSystem : public System {
public:
+ /**
+ * \brief Gets the singleton instance of RenderSystem.
+ * \return Reference to the RenderSystem instance.
+ */
static RenderSystem & get_instance();
- void update();
+
+ /**
+ * \brief Updates the RenderSystem for the current frame.
+ * This method is called to perform all rendering operations for the current game frame.
+ */
+ void update() override;
private:
+ // Private constructor to enforce singleton pattern.
RenderSystem();
~RenderSystem();
+
+ //! Clears the screen in preparation for rendering.
+ void clear_screen() const;
+
+ //! Presents the rendered frame to the display.
+ void present_screen() const;
+
+ //! Updates the active camera used for rendering.
+ void update_camera();
+
+ //! Renders all active sprites to the screen.
+ void render_sprites() const;
+
+ /**
+ * \todo Include color handling for sprites.
+ * \todo Implement particle emitter rendering with sprites.
+ * \todo Add text rendering using SDL_ttf for text components.
+ * \todo Implement a text component and a button component.
+ * \todo Ensure each sprite is checked for active status before rendering.
+ * \todo Sort all layers by order before rendering.
+ * \todo Consider adding text input functionality.
+ */
+
+private:
+ //! Pointer to the current active camera for rendering
+ Camera * curr_cam = nullptr;
+ // TODO: needs a better solution
};
} // namespace crepe