diff --git a/assets/sprites/neocat_64.png b/assets/sprites/neocat_64.png new file mode 100644 index 0000000..b8c0957 Binary files /dev/null and b/assets/sprites/neocat_64.png differ diff --git a/assets/sprites/neofox_64.png b/assets/sprites/neofox_64.png new file mode 100644 index 0000000..b00da05 Binary files /dev/null and b/assets/sprites/neofox_64.png differ diff --git a/src/core/drawing/sprite.cppm b/src/core/drawing/sprite.cppm new file mode 100644 index 0000000..a927b02 --- /dev/null +++ b/src/core/drawing/sprite.cppm @@ -0,0 +1,84 @@ +module; + +#include +#include +#include +#include + +export module core.drawing.sprite; + +import core.render_server; +import wrappers.sdl; + +export namespace core +{ + class Sprite + { + // Texture ID (managed by TextureManager in RenderServer) + TextureID texture_id_; + + // Texture source boundaries: which part of the texture to render + sdl::FRect texture_boundaries_; + + // Texture offset: static offset that is added to the render position (BEFORE scale is applied) + sdl::FPoint texture_offset_{0, 0}; + + // Texture scale: factors applied to width/height (AFTER offset is applied) + // TODO: Proper vector class? + sdl::FPoint texture_scale_{1, 1}; + + // Sprite position: where to render the sprite (world coordinates) + sdl::FPoint position_{0, 0}; + + public: + explicit Sprite( + const TextureID texture_id, + const sdl::FRect texture_boundaries, + const sdl::FPoint position, + const sdl::FPoint texture_offset = {0, 0}, + const sdl::FPoint texture_scale = {1, 1} + ) + : texture_id_{texture_id}, + texture_boundaries_{texture_boundaries}, + texture_offset_{texture_offset}, + texture_scale_{texture_scale}, + position_{position} + { + assert(texture_boundaries_.w > 0 && texture_boundaries_.h > 0); + } + + static Sprite create_with_texture( + RenderServer& render_server, + const std::string& filename, + std::optional texture_boundaries, + auto... args + ) + { + const TextureID texture_id = render_server.load_texture(filename); + + if (!texture_boundaries.has_value()) { + const sdl::Texture& texture = render_server.get_texture(texture_id); + texture_boundaries = texture.get_boundaries(); + } + + return Sprite(texture_id, texture_boundaries.value(), args...); + } + + void set_position(const sdl::FPoint new_position) + { + position_ = new_position; + } + + void draw(const RenderServer& render_server) const + { + const sdl::FRect dest_rect{ + position_.x + (texture_scale_.x * texture_offset_.x), + position_.y + (texture_scale_.y * texture_offset_.y), + texture_scale_.x * texture_boundaries_.w, + texture_scale_.y * texture_boundaries_.h, + }; + + render_server.render_texture(texture_id_, &texture_boundaries_, &dest_rect); + } + }; +} diff --git a/src/core/render_server.cppm b/src/core/render_server.cppm index c159769..bcb4c9f 100644 --- a/src/core/render_server.cppm +++ b/src/core/render_server.cppm @@ -43,13 +43,21 @@ export namespace core } /** - * Loads a texture from a file (if not loaded yet) and returns its texture ID. + * Load a texture from a file (if not loaded yet) and return its texture ID. */ constexpr TextureID load_texture(const std::string& filename) { return texture_manager_.load_resource_by_name(filename); } + /** + * Get a reference to a texture by its texture ID. + */ + constexpr const sdl::Texture& get_texture(const TextureID texture_id) const + { + return texture_manager_.get_resource(texture_id); + } + void start_frame() const { renderer_.clear(); @@ -60,16 +68,16 @@ export namespace core renderer_.present(); } - constexpr void render_texture( + void render_texture( const TextureID texture_id, const sdl::FRect* src_rect, const sdl::FRect* dest_rect ) const { - render_texture(texture_manager_.get_resource(texture_id), src_rect, dest_rect); + render_texture(get_texture(texture_id), src_rect, dest_rect); } - void render_texture( + constexpr void render_texture( const sdl::Texture& texture, const sdl::FRect* src_rect, const sdl::FRect* dest_rect diff --git a/src/game/game.cppm b/src/game/game.cppm index 7f7eab0..213cb50 100644 --- a/src/game/game.cppm +++ b/src/game/game.cppm @@ -2,14 +2,15 @@ module; #include #include +#include #include #include export module game.game; +import core.drawing.sprite; import core.engine; import core.render_server; -import game.sprite; import wrappers.sdl; import wrappers.sdl_image; @@ -24,15 +25,20 @@ export namespace game core::Engine& engine_; // Sprites for testing - Sprite player_sprite_; - std::vector sprites_; + core::Sprite player_sprite_; + std::vector sprites_; // Private constructor explicit Game(core::Engine& engine) : engine_(engine), player_sprite_{ - engine_.get_render_server().load_texture("assets/neocat.png"), - sdl::FRect{0, 0, 100, 100} + core::Sprite::create_with_texture( + engine_.get_render_server(), + "assets/sprites/neocat_64.png", + std::nullopt, + sdl::FPoint{0, 0}, + sdl::FPoint{-32, -32} + ) } {} @@ -63,21 +69,19 @@ export namespace game bool handle_event(const sdl::Event* event) { if (event->type == sdl::EventType::MouseMotion) { - player_sprite_.move( - event->motion.x - 50, - event->motion.y - 50 - ); + player_sprite_.set_position({event->motion.x, event->motion.y}); return true; } if (event->type == sdl::EventType::MouseButtonUp) { - sprites_.emplace_back( - engine_.get_render_server().load_texture("assets/neofox.png"), - sdl::FRect{ - event->motion.x - 50, - event->motion.y - 50, - 100, 100 - } + sprites_.push_back( + core::Sprite::create_with_texture( + engine_.get_render_server(), + "assets/sprites/neofox_64.png", + std::nullopt, + sdl::FPoint{event->motion.x, event->motion.y}, + sdl::FPoint{-32, -32} + ) ); return true; } @@ -94,7 +98,7 @@ export namespace game const auto& render_server = engine_.get_render_server(); render_server.start_frame(); - for (const Sprite& sprite : sprites_) { + for (const core::Sprite& sprite : sprites_) { sprite.draw(render_server); } player_sprite_.draw(render_server); diff --git a/src/game/sprite.cppm b/src/game/sprite.cppm deleted file mode 100644 index cd297c3..0000000 --- a/src/game/sprite.cppm +++ /dev/null @@ -1,35 +0,0 @@ -module; - -#include - -export module game.sprite; - -import core.render_server; -import wrappers.sdl; - -// TODO: Move this to a different namespace (core, drawing, ...?) -export namespace game -{ - class Sprite - { - core::TextureID texture_id_; - sdl::FRect dest_rect_{0, 0, 0, 0}; - - public: - explicit Sprite(const core::TextureID texture_id, const sdl::FRect dest_rect) - : texture_id_{texture_id}, - dest_rect_{dest_rect} - {} - - void move(const float x, const float y) - { - dest_rect_.x = x; - dest_rect_.y = y; - } - - void draw(const core::RenderServer& render_server) const - { - render_server.render_texture(texture_id_, nullptr, &dest_rect_); - } - }; -} diff --git a/src/wrappers/sdl/render.cppm b/src/wrappers/sdl/render.cppm index e0b28c0..0cf34e1 100644 --- a/src/wrappers/sdl/render.cppm +++ b/src/wrappers/sdl/render.cppm @@ -35,6 +35,21 @@ export namespace sdl assert(raw_texture_); return raw_texture_.get(); } + + constexpr int get_width() const + { + return raw_texture_->w; + } + + constexpr int get_height() const + { + return raw_texture_->h; + } + + constexpr FRect get_boundaries() const + { + return {0, 0, static_cast(raw_texture_->w), static_cast(raw_texture_->h)}; + } }; /**