diff options
| -rw-r--r-- | src/crepe/api/Animator.cpp | 48 | ||||
| -rw-r--r-- | src/crepe/api/Animator.h | 101 | ||||
| -rw-r--r-- | src/crepe/api/Camera.cpp | 9 | ||||
| -rw-r--r-- | src/crepe/api/Camera.h | 26 | ||||
| -rw-r--r-- | src/crepe/api/Config.h | 2 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.cpp | 1 | ||||
| -rw-r--r-- | src/crepe/api/Sprite.cpp | 16 | ||||
| -rw-r--r-- | src/crepe/api/Sprite.h | 82 | ||||
| -rw-r--r-- | src/crepe/api/Transform.h | 2 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.cpp | 117 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.h | 29 | ||||
| -rw-r--r-- | src/crepe/system/AnimatorSystem.cpp | 27 | ||||
| -rw-r--r-- | src/crepe/system/AnimatorSystem.h | 7 | ||||
| -rw-r--r-- | src/crepe/system/RenderSystem.cpp | 21 | ||||
| -rw-r--r-- | src/crepe/system/RenderSystem.h | 11 | ||||
| -rw-r--r-- | src/example/rendering_particle.cpp | 73 | ||||
| -rw-r--r-- | src/test/ParticleTest.cpp | 6 | ||||
| -rw-r--r-- | src/test/RenderSystemTest.cpp | 132 | 
18 files changed, 457 insertions, 253 deletions
| diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 45f67f6..dc99fd4 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -7,21 +7,53 @@  using namespace crepe; -Animator::Animator(game_object_id_t id, Sprite & ss, int row, int col, int col_animator) +Animator::Animator(uint32_t id, Sprite & ss, int max_row, int max_col, +				   const Animator::Data & ctx)  	: Component(id),  	  spritesheet(ss), -	  row(row), -	  col(col) { +	  row(max_row), +	  col(max_col), +	  data(ctx) {  	dbg_trace(); -	this->spritesheet.mask.h /= col; -	this->spritesheet.mask.w /= row; -	this->spritesheet.mask.x = 0; -	this->spritesheet.mask.y = col_animator * this->spritesheet.mask.h; -	this->active = false; +	this->spritesheet.mask.h /= this->col; +	this->spritesheet.mask.w /= this->row; +	this->spritesheet.mask.x = this->data.curr_row * this->spritesheet.mask.w; +	this->spritesheet.mask.y = this->data.curr_col * this->spritesheet.mask.h;  	// need to do this for to get the aspect ratio for a single clipping in the spritesheet  	this->spritesheet.aspect_ratio  		= static_cast<double>(this->spritesheet.mask.w) / this->spritesheet.mask.h;  } +  Animator::~Animator() { dbg_trace(); } + +void Animator::loop() { this->data.looping = true; } + +void Animator::play() { this->active = true; } + +void Animator::pause() { this->active = false; } + +void Animator::stop() { +	this->active = false; +	this->data.curr_col = 0; +	this->data.curr_row = 0; +} +void Animator::set_fps(int fps) { this->data.fps = fps; } + +void Animator::set_cycle_range(int start, int end) { +	this->data.cycle_start = start, this->data.cycle_end = end; +} + +void Animator::set_anim(int col) { +	Animator::Data & ctx = this->data; +	this->spritesheet.mask.x = ctx.curr_row = 0; +	ctx.curr_col = col; +	this->spritesheet.mask.y = ctx.curr_col * this->spritesheet.mask.h; +} + +void Animator::next_anim() { +	Animator::Data & ctx = this->data; +	ctx.curr_row = ctx.curr_row++ % this->row; +	this->spritesheet.mask.x = ctx.curr_row * this->spritesheet.mask.w; +} diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h index 6c506aa..dab6697 100644 --- a/src/crepe/api/Animator.h +++ b/src/crepe/api/Animator.h @@ -16,33 +16,100 @@ class SDLContext;   * sheet. It can be used to play animations, loop them, or stop them.   */  class Animator : public Component { +public: +	struct Data { + +		//! frames per second for animation +		int fps = 1; + +		//! The current col being animated. +		int curr_col = 0; + +		//! The current row being animated. +		int curr_row = 0; + +		//! should the animation loop +		bool looping = false; + +		//! starting frame for cycling +		int cycle_start = 0; + +		//! end frame for cycling (-1 --> use last frame) +		int cycle_end = -1; + +		//! offset in pixels. +		// TODO implement +		int offset_x = 0; +	};  public: -	//TODO: need to implement this +	/** +	 * \brief Animator will repeat the animation  +	 * +	 */  	void loop(); + +	/** +	 * \brief starts the animation +	 * +	 */ +	void play(); +	/** +	 * \brief pauses the animation +	 * +	 * sets the active false +	 * +	 */ +	void pause(); + +	/** +	 * \brief stops the animation +	 * +	 * sets the active on false and resets all the current rows and columns +	 * +	 */  	void stop(); +	/** +	 * \brief set frames per second +	 * +	 * \param fps frames per second +	 */ +	void set_fps(int fps); +	/** +	 * \brief set the range in the row +	 * +	 * \param  start of row animation +	 * \param  end of row animation	 +	 */ +	void set_cycle_range(int start, int end); +	/** +	 * \brief select which column to animate from +	 * +	 * \param col animation column +	 */ +	void set_anim(int col); + +	/** +	 * \brief will go to the next animaiton of current row  +	 * +	 */ +	void next_anim();  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. +	 * \param ctx animator data  	 *  	 * 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(uint32_t id, Sprite & ss, int max_row, int max_col, const Animator::Data & ctx);  	~Animator(); // dbg_trace -private: -	//! A reference to the Sprite sheet containing the animation frames. +public: +	//! A reference to the Sprite sheet containing.  	Sprite & spritesheet;  	//! The maximum number of columns in the sprite sheet. @@ -51,21 +118,11 @@ private:  	//! 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; - -	//TODO: Is this necessary? -	//int fps; +	Animator::Data data;  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/Camera.cpp b/src/crepe/api/Camera.cpp index 39d8ab0..b042c35 100644 --- a/src/crepe/api/Camera.cpp +++ b/src/crepe/api/Camera.cpp @@ -2,19 +2,16 @@  #include "util/Log.h"  #include "Camera.h" -#include "Color.h"  #include "Component.h"  using namespace crepe; -Camera::Camera(game_object_id_t id, const Color & bg_color, const ivec2 & screen, -			   const vec2 & viewport_size, const double & zoom, const vec2 & offset) +Camera::Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, +			   const Data & ctx)  	: Component(id), -	  bg_color(bg_color), -	  offset(offset),  	  screen(screen),  	  viewport_size(viewport_size), -	  zoom(zoom) { +	  data(ctx) {  	dbg_trace();  } diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h index 2d8fa48..f626379 100644 --- a/src/crepe/api/Camera.h +++ b/src/crepe/api/Camera.h @@ -14,23 +14,30 @@ namespace crepe {   * position, and zoom level. It controls what part of the game world is visible on the screen.   */  class Camera : public Component { +public: +	struct Data { +		//! Background color of the camera view. +		const Color bg_color = Color::WHITE; + +		//! Zoom level of the camera view. +		double zoom = 1; + +		//! offset postion from the game object transform component +		vec2 offset; +	};  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. +	 * \param ctx the camera component data  	 */ -	Camera(game_object_id_t id, const Color & bg_color, const ivec2 & screen, -		   const vec2 & viewport_size, const double & zoom, const vec2 & offset = {0, 0}); +	Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, +		   const Data & ctx);  	~Camera(); // dbg_trace only  public: -	//! Background color of the camera view. -	const Color bg_color; - -	//! offset postion from the game object transform component -	vec2 offset; +	Camera::Data data;  	//! screen the display size in pixels ( output resolution )  	const ivec2 screen; @@ -38,9 +45,6 @@ public:  	//! viewport is the area of the world visible through the camera (in world units)  	const vec2 viewport_size; -	//! Zoom level of the camera view. -	const double zoom; -  public:  	/**  	 * \brief Gets the maximum number of camera instances allowed. diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 225e9b9..200a3b0 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -67,7 +67,7 @@ public:  	//! default window settings  	struct {  		//TODO make this constexpr because this will never change -		ivec2 default_size = {1080, 720}; +		ivec2 default_size = {1280, 720};  		std::string window_title = "Jetpack joyride clone";  	} window_settings; diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index dc2d9e0..3e9a88e 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -60,6 +60,7 @@ void LoopManager::setup() {  	this->game_running = true;  	timer.start();  	timer.set_fps(200); +	this->scene_manager.load_next_scene();  }  void LoopManager::render() { diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index 0a2ad4c..b52a344 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -6,24 +6,20 @@  #include "Component.h"  #include "Sprite.h"  #include "Texture.h" +#include "types.h"  using namespace std;  using namespace crepe; -Sprite::Sprite(game_object_id_t id, Texture & image, const Color & color, -			   const FlipSettings & flip, int sort_layer, int order_layer, int height) +Sprite::Sprite(game_object_id_t id, Texture & texture, const Sprite::Data & ctx)  	: Component(id), -	  color(color), -	  flip(flip), -	  sprite_image(std::move(image)), -	  sorting_in_layer(sort_layer), -	  order_in_layer(order_layer), -	  height(height) { +	  texture(std::move(texture)), +	  data(ctx) {  	dbg_trace(); -	this->mask.w = sprite_image.get_size().x; -	this->mask.h = sprite_image.get_size().y; +	this->mask.w = this->texture.get_size().x; +	this->mask.h = this->texture.get_size().y;  	this->aspect_ratio = static_cast<double>(this->mask.w) / this->mask.h;  } diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index a0e90a0..a1230db 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -1,11 +1,10 @@  #pragma once -#include <cstdint> -  #include "../Component.h"  #include "Color.h"  #include "Texture.h" +#include "types.h"  namespace crepe { @@ -20,60 +19,67 @@ class AnimatorSystem;   * flip settings, and is managed in layers with defined sorting orders.   */  class Sprite : public Component { -  public:  	struct FlipSettings {  		bool flip_x = false;  		bool flip_y = false;  	}; +	struct Data { +		//! Color tint of the sprite +		Color color = Color::WHITE; + +		//! Flip settings for the sprite +		FlipSettings flip; + +		//! Layer sorting level of the sprite +		const int sorting_in_layer = 0; + +		//! Order within the sorting layer +		const int order_in_layer = 0; + +		/** +	 	* \size width and height of the sprite in game units +	 	* +	 	* if height is filled in and not width it will multiply width by aspect_ratio. +	 	* if width is filled in and not height it will multiply height by aspect_ratio. +	 	* if neither is filled it will not show sprite because size will be zero +	 	* if both are filled will it use the width and height without making sure the aspect_ratio +	 	* is correct +	 	*/ +		vec2 size; + +		//! independent sprite angle. rotating clockwise direction in degrees +		double angle_offset = 0; + +		//! independent sprite scale multiplier +		double scale_offset = 1; +	}; +  public: -	// 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. -	 * \param order_layer decides the sorting in layer of the sprite. -	 * \param sort_layer decides the order in layer of the sprite. -	 * \param height the height of the image in game units -	 */ -	Sprite(game_object_id_t id, Texture & image, const Color & color, -		   const FlipSettings & flip, int sort_layer, int order_layer, int height); - -	/** -	 * \brief Destroys the Sprite instance. +	 * \param texture asset of the image +	 * \param ctx all the sprite data  	 */ +	Sprite(game_object_id_t id, Texture & texture, const Data & ctx);  	~Sprite();  	//! Texture used for the sprite -	const Texture sprite_image; - -	//! Color tint of the sprite -	Color color; - -	//! Flip settings for the sprite -	FlipSettings flip; +	const Texture texture; -	//! Layer sorting level of the sprite -	const int sorting_in_layer; -	//! Order within the sorting layer -	const int order_in_layer; - -	//! height in world units -	const int height; +	Data data; +private:  	/** -	 * \aspect_ratio ratio of the img so that scaling will not become weird -	 * -	 * cannot be const because if Animator component is addded then ratio becomes scuffed and -	 * does it need to be calculated again in the Animator -	 */ -	double aspect_ratio; +		* \aspect_ratio ratio of the img so that scaling will not become weird +		* +		* cannot be const because if Animator component is addded then ratio becomes scuffed and +		* does it need to be calculated again in the Animator +		*/ +	float aspect_ratio; -private:  	//! Reads the mask of sprite  	friend class SDLContext; diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h index 6243a93..34ac70a 100644 --- a/src/crepe/api/Transform.h +++ b/src/crepe/api/Transform.h @@ -15,7 +15,7 @@ class Transform : public Component {  public:  	//! Translation (shift)  	vec2 position = {0, 0}; -	//! Rotation, in degrees +	//! Rotation, in degrees clockwise  	double rotation = 0;  	//! Multiplication factor  	double scale = 0; diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index ad9f1f0..72b4e42 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -215,11 +215,13 @@ MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) {  	return MOUSE_BUTTON_LOOKUP_TABLE[sdl_button];  } -void SDLContext::clear_screen() { +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{ @@ -229,40 +231,57 @@ 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 DstRect & 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.x == 0 && data.size.y != 0 ? data.size.y * ctx.sprite.aspect_ratio +													  : data.size.x, +				 data.size.y == 0 && data.size.x != 0 ? data.size.x / ctx.sprite.aspect_ratio +													  : data.size.y}; + +	const CameraValues & cam = ctx.cam; + +	size *= cam.render_scale * ctx.img_scale * data.scale_offset; + +	vec2 screen_pos = (ctx.pos - 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_FRect dstrect = this->get_dst_rect(SDLContext::DstRect{ +		.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.sprite_image, ctx.sprite.color); -	SDL_RenderCopyEx(this->game_renderer.get(), ctx.sprite.sprite_image.texture.get(), -					 &srcrect, &dstrect, ctx.angle, NULL, render_flip); +	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); @@ -270,42 +289,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; +	double screen_aspect = static_cast<double>(cam.screen.x) / cam.screen.y; +	double 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(); } diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index a2b34c1..dfdaa56 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -33,10 +33,17 @@ class InputSystem;   */  class SDLContext {  public: +	//! data that the camera component cannot hold +	struct CameraValues { +		vec2 zoomed_viewport; +		vec2 render_scale; +		vec2 bar_size; +		vec2 cam_pos; +	}; +  	struct RenderContext {  		const Sprite & sprite; -		const Camera & cam; -		const vec2 & cam_pos; +		const CameraValues & cam;  		const vec2 & pos;  		const double & angle;  		const double & scale; @@ -114,8 +121,6 @@ private:  	MouseButton sdl_to_mousebutton(Uint8 sdl_button);  private: -	//! Will only use get_ticks -	friend class AnimatorSystem;  	//! Will only use delay  	friend class LoopTimer;  	/** @@ -170,7 +175,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); @@ -184,9 +189,15 @@ 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: +	struct DstRect { +		const Sprite & sprite; +		const CameraValues & cam; +		const vec2 & pos; +		const double & img_scale; +	};  	/**  	 * \brief calculates the sqaure size of the image  	 * @@ -205,8 +216,7 @@ private:  	 * \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 DstRect & ctx) const;  	/**  	 * \brief Set an additional color value multiplied into render copy operations.  	 * @@ -221,6 +231,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/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp index 8bb6465..9aede7f 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -1,4 +1,4 @@ -#include <cstdint> +  #include "../api/Animator.h"  #include "../facade/SDLContext.h" @@ -13,12 +13,27 @@ void AnimatorSystem::update() {  	RefVector<Animator> animations = mgr.get_components_by_type<Animator>(); -	uint64_t tick = SDLContext::get_instance().get_ticks(); +	double elapsed_time = this->timer.get_current_time(); +  	for (Animator & a : animations) {  		if (!a.active) continue; -		// (10 frames per second) -		a.curr_row = (tick / 100) % a.row; -		a.spritesheet.mask.x = (a.curr_row * a.spritesheet.mask.w) + a.curr_col; -		a.spritesheet.mask = a.spritesheet.mask; + +		Animator::Data & ctx = a.data; +		double frame_duration = 1.0f / ctx.fps; + +		int last_frame = ctx.curr_row; + +		int cycle_end = (ctx.cycle_end == -1) ? a.row : ctx.cycle_end; +		int total_frames = cycle_end - ctx.cycle_start; + +		int curr_frame = static_cast<int>(elapsed_time / frame_duration) % total_frames; + +		ctx.curr_row = ctx.cycle_start + curr_frame; +		a.spritesheet.mask.x = ctx.curr_row * a.spritesheet.mask.w; +		a.spritesheet.mask.y = (ctx.curr_col * a.spritesheet.mask.h); + +		if (!ctx.looping && curr_frame == ctx.cycle_start && last_frame == total_frames - 1) { +			a.active = false; +		}  	}  } diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h index f8179a9..e8a5158 100644 --- a/src/crepe/system/AnimatorSystem.h +++ b/src/crepe/system/AnimatorSystem.h @@ -1,9 +1,7 @@  #pragma once  #include "System.h" - -//TODO: -// control if flip works with animation system +#include "api/LoopTimer.h"  namespace crepe { @@ -26,6 +24,9 @@ public:  	 * looping).  	 */  	void update() override; + +private: +	LoopTimer & timer = LoopTimer::get_instance();  };  } // namespace crepe diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 92dba43..111ad7d 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -21,7 +21,7 @@ void RenderSystem::clear_screen() { this->context.clear_screen(); }  void RenderSystem::present_screen() { this->context.present_screen(); } -const Camera & RenderSystem::update_camera() { +SDLContext::CameraValues RenderSystem::update_camera() {  	ComponentManager & mgr = this->mediator.component_manager;  	RefVector<Camera> cameras = mgr.get_components_by_type<Camera>(); @@ -32,16 +32,17 @@ const Camera & RenderSystem::update_camera() {  		if (!cam.active) continue;  		const Transform & transform  			= mgr.get_components_by_id<Transform>(cam.game_object_id).front().get(); -		this->context.set_camera(cam); -		this->cam_pos = transform.position + cam.offset; -		return cam; +		SDLContext::CameraValues cam_val = this->context.set_camera(cam); +		cam_val.cam_pos = transform.position + cam.data.offset; +		return cam_val;  	}  	throw std::runtime_error("No active cameras in current scene");  }  bool sorting_comparison(const Sprite & a, const Sprite & b) { -	if (a.sorting_in_layer < b.sorting_in_layer) return true; -	if (a.sorting_in_layer == b.sorting_in_layer) return a.order_in_layer < b.order_in_layer; +	if (a.data.sorting_in_layer < b.data.sorting_in_layer) return true; +	if (a.data.sorting_in_layer == b.data.sorting_in_layer) +		return a.data.order_in_layer < b.data.order_in_layer;  	return false;  } @@ -59,7 +60,7 @@ void RenderSystem::update() {  	this->present_screen();  } -bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam, +bool RenderSystem::render_particle(const Sprite & sprite, const SDLContext::CameraValues & cam,  								   const double & scale) {  	ComponentManager & mgr = this->mediator.component_manager; @@ -80,7 +81,6 @@ bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam,  			this->context.draw(SDLContext::RenderContext{  				.sprite = sprite,  				.cam = cam, -				.cam_pos = this->cam_pos,  				.pos = p.position,  				.angle = p.angle,  				.scale = scale, @@ -89,12 +89,11 @@ bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam,  	}  	return rendering_particles;  } -void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam, +void RenderSystem::render_normal(const Sprite & sprite, const SDLContext::CameraValues & cam,  								 const Transform & tm) {  	this->context.draw(SDLContext::RenderContext{  		.sprite = sprite,  		.cam = cam, -		.cam_pos = this->cam_pos,  		.pos = tm.position,  		.angle = tm.rotation,  		.scale = tm.scale, @@ -103,7 +102,7 @@ void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam,  void RenderSystem::render() {  	ComponentManager & mgr = this->mediator.component_manager; -	const Camera & cam = this->update_camera(); +	const SDLContext::CameraValues & cam = this->update_camera();  	RefVector<Sprite> sprites = mgr.get_components_by_type<Sprite>();  	RefVector<Sprite> sorted_sprites = this->sort(sprites); diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 096d058..eaf1213 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -37,7 +37,7 @@ private:  	void present_screen();  	//! Updates the active camera used for rendering. -	const Camera & update_camera(); +	SDLContext::CameraValues update_camera();  	//! Renders the whole screen  	void render(); @@ -52,7 +52,8 @@ private:  	 *  constructor is now protected i cannot make tmp inside  	 * \return true if particles have been rendered  	 */ -	bool render_particle(const Sprite & sprite, const Camera & cam, const double & scale); +	bool render_particle(const Sprite & sprite, const SDLContext::CameraValues & cam, +						 const double & scale);  	/**  	 * \brief renders a sprite with a Transform component on the screen  @@ -60,7 +61,8 @@ private:  	 * \param sprite  the sprite component that holds all the data  	 * \param tm the Transform component that holds the position,rotation and scale   	 */ -	void render_normal(const Sprite & sprite, const Camera & cam, const Transform & tm); +	void render_normal(const Sprite & sprite, const SDLContext::CameraValues & cam, +					   const Transform & tm);  	/**  	 * \brief sort a vector sprite objects with @@ -79,9 +81,6 @@ private:  private:  	// FIXME: retrieve sdlcontext via mediator after #PR57  	SDLContext & context = SDLContext::get_instance(); - -	//! camera postion in the current scene -	vec2 cam_pos;  };  } // namespace crepe diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 349d11e..07e43a1 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -1,5 +1,7 @@  #include "api/Animator.h"  #include "api/Camera.h" +#include "api/LoopManager.h" +#include "api/LoopTimer.h"  #include "system/AnimatorSystem.h"  #include "system/ParticleSystem.h"  #include <SDL2/SDL_timer.h> @@ -16,28 +18,10 @@  #include <crepe/system/RenderSystem.h>  #include <crepe/types.h> -#include <chrono> -  using namespace crepe;  using namespace std; -int main(int argc, char * argv[]) { -	ComponentManager mgr; -	GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 1); -	RenderSystem sys{mgr}; -	ParticleSystem psys{mgr}; -	AnimatorSystem asys{mgr}; - -	Color color(255, 255, 255, 100); - -	auto img = Texture("asset/texture/test_ap43.png"); -	Sprite & test_sprite = game_object.add_component<Sprite>( -		img, color, Sprite::FlipSettings{true, true}, 1, 1, 500); - -	//game_object.add_component<Animator>(test_sprite, 4, 1, 0).active = true; -	game_object.add_component<Animator>(test_sprite, 1, 1, 0).active = true; - -	/* +/*  	auto & test = game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{  		.position = {0, 0},  		.max_particles = 10, @@ -59,8 +43,47 @@ int main(int argc, char * argv[]) {  	});  	*/ -	auto & cam = game_object.add_component<Camera>(Color::RED, ivec2{1080, 720}, -												   vec2{2000, 2000}, 1.0f); +class TestScene : public Scene { +public: +	void load_scene() { +		ComponentManager & mgr = this->component_manager; +		GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 1); + +		Color color(255, 255, 255, 255); + +		auto img = Texture("asset/spritesheet/pokemon_spritesheet.png"); + +		Sprite & test_sprite = game_object.add_component<Sprite>( +			img, Sprite::Data{ +					 .color = color, +					 .flip = Sprite::FlipSettings{false, false}, +					 .sorting_in_layer = 2, +					 .order_in_layer = 2, +					 .size = {0, 100}, +					 .angle_offset = 0, +				 }); + +		auto & anim = game_object.add_component<Animator>(test_sprite, 4, 4, +														  Animator::Data{ +															  .fps = 1, +															  .looping = false, +														  }); +		anim.set_anim(2); +		anim.active = false; + +		auto & cam = game_object.add_component<Camera>(ivec2{1280, 720}, vec2{400, 400}, +													   Camera::Data{ +														   .bg_color = Color::WHITE, +													   }); +	} + +	string get_name() const { return "TestScene"; }; +}; + +int main(int argc, char * argv[]) { +	LoopManager engine; +	engine.add_scene<TestScene>(); +	engine.start();  	/*  	game_object @@ -71,13 +94,5 @@ int main(int argc, char * argv[]) {  		= 6;  	*/ -	auto start = std::chrono::steady_clock::now(); -	while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { -		psys.update(); -		asys.update(); -		sys.update(); -		SDL_Delay(10); -	} -  	return 0;  } diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index a659fe5..1409c4f 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -32,7 +32,11 @@ public:  			Color color(0, 0, 0, 0);  			auto s1 = Texture("asset/texture/img.png");  			Sprite & test_sprite = game_object.add_component<Sprite>( -				s1, color, Sprite::FlipSettings{true, true}, 1, 1, 100); +				s1, Sprite::Data{ +						.color = color, +						.flip = Sprite::FlipSettings{true, true}, +						.size = {10, 10}, +					});  			game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{  				.position = {0, 0}, diff --git a/src/test/RenderSystemTest.cpp b/src/test/RenderSystemTest.cpp index c105dcb..4868ddd 100644 --- a/src/test/RenderSystemTest.cpp +++ b/src/test/RenderSystemTest.cpp @@ -35,28 +35,50 @@ public:  		auto s2 = Texture("asset/texture/img.png");  		auto s3 = Texture("asset/texture/img.png");  		auto s4 = Texture("asset/texture/img.png"); -		auto & sprite1 = entity1.add_component<Sprite>( -			s1, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 5, 5, 100); -		ASSERT_NE(sprite1.sprite_image.texture.get(), nullptr); -		EXPECT_EQ(sprite1.order_in_layer, 5); -		EXPECT_EQ(sprite1.sorting_in_layer, 5); -		auto & sprite2 = entity2.add_component<Sprite>( -			s2, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 2, 1, 100); -		ASSERT_NE(sprite2.sprite_image.texture.get(), nullptr); -		EXPECT_EQ(sprite2.sorting_in_layer, 2); -		EXPECT_EQ(sprite2.order_in_layer, 1); - -		auto & sprite3 = entity3.add_component<Sprite>( -			s3, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 1, 2, 100); -		ASSERT_NE(sprite3.sprite_image.texture.get(), nullptr); -		EXPECT_EQ(sprite3.sorting_in_layer, 1); -		EXPECT_EQ(sprite3.order_in_layer, 2); - -		auto & sprite4 = entity4.add_component<Sprite>( -			s4, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 1, 1, 100); -		ASSERT_NE(sprite4.sprite_image.texture.get(), nullptr); -		EXPECT_EQ(sprite4.sorting_in_layer, 1); -		EXPECT_EQ(sprite4.order_in_layer, 1); +		auto & sprite1 +			= entity1.add_component<Sprite>(s1, Sprite::Data{ +													.color = Color(0, 0, 0, 0), +													.flip = Sprite::FlipSettings{false, false}, +													.sorting_in_layer = 5, +													.order_in_layer = 5, +													.size = {10, 10}, +												}); + +		ASSERT_NE(sprite1.texture.texture.get(), nullptr); +		EXPECT_EQ(sprite1.data.order_in_layer, 5); +		EXPECT_EQ(sprite1.data.sorting_in_layer, 5); +		auto & sprite2 +			= entity2.add_component<Sprite>(s2, Sprite::Data{ +													.color = Color(0, 0, 0, 0), +													.flip = Sprite::FlipSettings{false, false}, +													.sorting_in_layer = 2, +													.order_in_layer = 1, +												}); +		ASSERT_NE(sprite2.texture.texture.get(), nullptr); +		EXPECT_EQ(sprite2.data.sorting_in_layer, 2); +		EXPECT_EQ(sprite2.data.order_in_layer, 1); + +		auto & sprite3 +			= entity3.add_component<Sprite>(s3, Sprite::Data{ +													.color = Color(0, 0, 0, 0), +													.flip = Sprite::FlipSettings{false, false}, +													.sorting_in_layer = 1, +													.order_in_layer = 2, +												}); +		ASSERT_NE(sprite3.texture.texture.get(), nullptr); +		EXPECT_EQ(sprite3.data.sorting_in_layer, 1); +		EXPECT_EQ(sprite3.data.order_in_layer, 2); + +		auto & sprite4 +			= entity4.add_component<Sprite>(s4, Sprite::Data{ +													.color = Color(0, 0, 0, 0), +													.flip = Sprite::FlipSettings{false, false}, +													.sorting_in_layer = 1, +													.order_in_layer = 1, +												}); +		ASSERT_NE(sprite4.texture.texture.get(), nullptr); +		EXPECT_EQ(sprite4.data.sorting_in_layer, 1); +		EXPECT_EQ(sprite4.data.order_in_layer, 1);  	}  }; @@ -66,8 +88,13 @@ TEST_F(RenderSystemTest, expected_throws) {  	// no texture img  	EXPECT_ANY_THROW({  		auto test = Texture(""); -		entity1.add_component<Sprite>(test, Color(0, 0, 0, 0), -									  Sprite::FlipSettings{false, false}, 1, 1, 100); +		auto & sprite1 = entity1.add_component<Sprite>( +			test, Sprite::Data{ +					  .color = Color(0, 0, 0, 0), +					  .flip = Sprite::FlipSettings{false, false}, +					  .sorting_in_layer = 1, +					  .order_in_layer = 1, +				  });  	});  	// No camera @@ -89,32 +116,35 @@ TEST_F(RenderSystemTest, sorting_sprites) {  	// 3. sorting_in_layer: 2, order_in_layer: 1 (entity2)  	// 4. sorting_in_layer: 5, order_in_layer: 5 (entity1) -	EXPECT_EQ(sorted_sprites[0].get().sorting_in_layer, 1); -	EXPECT_EQ(sorted_sprites[0].get().order_in_layer, 1); +	EXPECT_EQ(sorted_sprites[0].get().data.sorting_in_layer, 1); +	EXPECT_EQ(sorted_sprites[0].get().data.order_in_layer, 1); -	EXPECT_EQ(sorted_sprites[1].get().sorting_in_layer, 1); -	EXPECT_EQ(sorted_sprites[1].get().order_in_layer, 2); +	EXPECT_EQ(sorted_sprites[1].get().data.sorting_in_layer, 1); +	EXPECT_EQ(sorted_sprites[1].get().data.order_in_layer, 2); -	EXPECT_EQ(sorted_sprites[2].get().sorting_in_layer, 2); -	EXPECT_EQ(sorted_sprites[2].get().order_in_layer, 1); +	EXPECT_EQ(sorted_sprites[2].get().data.sorting_in_layer, 2); +	EXPECT_EQ(sorted_sprites[2].get().data.order_in_layer, 1); -	EXPECT_EQ(sorted_sprites[3].get().sorting_in_layer, 5); -	EXPECT_EQ(sorted_sprites[3].get().order_in_layer, 5); +	EXPECT_EQ(sorted_sprites[3].get().data.sorting_in_layer, 5); +	EXPECT_EQ(sorted_sprites[3].get().data.order_in_layer, 5);  	for (size_t i = 1; i < sorted_sprites.size(); ++i) {  		const Sprite & prev = sorted_sprites[i - 1].get();  		const Sprite & curr = sorted_sprites[i].get(); -		if (prev.sorting_in_layer == curr.sorting_in_layer) { -			EXPECT_LE(prev.order_in_layer, curr.order_in_layer); +		if (prev.data.sorting_in_layer == curr.data.sorting_in_layer) { +			EXPECT_LE(prev.data.order_in_layer, curr.data.order_in_layer);  		} else { -			EXPECT_LE(prev.sorting_in_layer, curr.sorting_in_layer); +			EXPECT_LE(prev.data.sorting_in_layer, curr.data.sorting_in_layer);  		}  	}  }  TEST_F(RenderSystemTest, Update) { -	entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); +	entity1.add_component<Camera>(Camera::Data{.bg_color = Color::WHITE, +											   .screen = ivec2{1080, 720}, +											   .viewport_size = vec2{2000, 2000}, +											   .zoom = 1.0f});  	{  		vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>();  		ASSERT_EQ(sprites.size(), 4); @@ -142,7 +172,10 @@ TEST_F(RenderSystemTest, Camera) {  		EXPECT_NE(cameras.size(), 1);  	}  	{ -		entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); +		entity1.add_component<Camera>(Camera::Data{.bg_color = Color::WHITE, +												   .screen = ivec2{1080, 720}, +												   .viewport_size = vec2{2000, 2000}, +												   .zoom = 1.0f});  		auto cameras = this->mgr.get_components_by_type<Camera>();  		EXPECT_EQ(cameras.size(), 1);  	} @@ -150,18 +183,21 @@ TEST_F(RenderSystemTest, Camera) {  	//TODO improve with newer version  }  TEST_F(RenderSystemTest, Color) { -	entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); +	entity1.add_component<Camera>(Camera::Data{.bg_color = Color::WHITE, +											   .screen = ivec2{1080, 720}, +											   .viewport_size = vec2{2000, 2000}, +											   .zoom = 1.0f});  	auto & sprite = this->mgr.get_components_by_id<Sprite>(entity1.id).front().get(); -	ASSERT_NE(sprite.sprite_image.texture.get(), nullptr); +	ASSERT_NE(sprite.texture.texture.get(), nullptr); -	sprite.color = Color::GREEN; -	EXPECT_EQ(sprite.color.r, Color::GREEN.r); -	EXPECT_EQ(sprite.color.g, Color::GREEN.g); -	EXPECT_EQ(sprite.color.b, Color::GREEN.b); -	EXPECT_EQ(sprite.color.a, Color::GREEN.a); +	sprite.data.color = Color::GREEN; +	EXPECT_EQ(sprite.data.color.r, Color::GREEN.r); +	EXPECT_EQ(sprite.data.color.g, Color::GREEN.g); +	EXPECT_EQ(sprite.data.color.b, Color::GREEN.b); +	EXPECT_EQ(sprite.data.color.a, Color::GREEN.a);  	this->sys.update(); -	EXPECT_EQ(sprite.color.r, Color::GREEN.r); -	EXPECT_EQ(sprite.color.g, Color::GREEN.g); -	EXPECT_EQ(sprite.color.b, Color::GREEN.b); -	EXPECT_EQ(sprite.color.a, Color::GREEN.a); +	EXPECT_EQ(sprite.data.color.r, Color::GREEN.r); +	EXPECT_EQ(sprite.data.color.g, Color::GREEN.g); +	EXPECT_EQ(sprite.data.color.b, Color::GREEN.b); +	EXPECT_EQ(sprite.data.color.a, Color::GREEN.a);  } |