diff options
Diffstat (limited to 'src/crepe')
| -rw-r--r-- | src/crepe/api/Animator.cpp | 23 | ||||
| -rw-r--r-- | src/crepe/api/Animator.h | 76 | ||||
| -rw-r--r-- | src/crepe/api/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/crepe/api/Camera.cpp | 17 | ||||
| -rw-r--r-- | src/crepe/api/Camera.h | 55 | ||||
| -rw-r--r-- | src/crepe/api/Color.cpp | 3 | ||||
| -rw-r--r-- | src/crepe/api/Color.h | 17 | ||||
| -rw-r--r-- | src/crepe/api/Sprite.cpp | 7 | ||||
| -rw-r--r-- | src/crepe/api/Sprite.h | 76 | ||||
| -rw-r--r-- | src/crepe/api/Texture.cpp | 15 | ||||
| -rw-r--r-- | src/crepe/api/Texture.h | 54 | ||||
| -rw-r--r-- | src/crepe/api/Transform.h | 2 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.cpp | 200 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.h | 118 | ||||
| -rw-r--r-- | src/crepe/system/AnimatorSystem.cpp | 37 | ||||
| -rw-r--r-- | src/crepe/system/AnimatorSystem.h | 44 | ||||
| -rw-r--r-- | src/crepe/system/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/crepe/system/RenderSystem.cpp | 36 | ||||
| -rw-r--r-- | src/crepe/system/RenderSystem.h | 49 | 
19 files changed, 705 insertions, 130 deletions
| 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 d3465c7..f9cd761 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,10 +10,13 @@  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/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 |