diff options
-rw-r--r-- | asset/texture/ERROR.png | bin | 0 -> 3581 bytes | |||
-rw-r--r-- | src/crepe/api/Texture.cpp | 2 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.cpp | 80 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.h | 37 | ||||
-rw-r--r-- | src/crepe/system/RenderSystem.cpp | 64 | ||||
-rw-r--r-- | src/crepe/system/RenderSystem.h | 25 | ||||
-rw-r--r-- | src/example/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/example/rendering_particle.cpp | 64 |
8 files changed, 218 insertions, 55 deletions
diff --git a/asset/texture/ERROR.png b/asset/texture/ERROR.png Binary files differnew file mode 100644 index 0000000..2af3548 --- /dev/null +++ b/asset/texture/ERROR.png diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp index de0d0ea..734a5bb 100644 --- a/src/crepe/api/Texture.cpp +++ b/src/crepe/api/Texture.cpp @@ -35,5 +35,5 @@ int Texture::get_width() const { } int Texture::get_height() const { if (this->texture == nullptr) return 0; - return SDLContext::get_instance().get_width(*this); + return SDLContext::get_instance().get_height(*this); } diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 83e91f8..daf0050 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -1,5 +1,6 @@ #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> +#include <SDL2/SDL_keycode.h> #include <SDL2/SDL_rect.h> #include <SDL2/SDL_render.h> #include <SDL2/SDL_surface.h> @@ -7,13 +8,15 @@ #include <cmath> #include <cstddef> #include <functional> -#include <iostream> #include <memory> +#include <stdexcept> #include <string> +#include "../api/Camera.h" #include "../api/Sprite.h" #include "../api/Texture.h" #include "../api/Transform.h" +#include "../api/Vector2.h" #include "../util/Log.h" #include "SDLContext.h" @@ -31,28 +34,20 @@ SDLContext::SDLContext() { // FIXME: read window defaults from config manager if (SDL_Init(SDL_INIT_VIDEO) < 0) { - // FIXME: throw exception - std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl; - return; + throw std::runtime_error("SDL could not initialize!"); } SDL_Window * tmp_window = SDL_CreateWindow("Crepe Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 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; + throw std::runtime_error("Window could not be created!"); } this->game_window = {tmp_window, [](SDL_Window * window) { SDL_DestroyWindow(window); }}; 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.get()); - return; + throw std::runtime_error("Renderer could not be created!"); } this->game_renderer @@ -60,9 +55,7 @@ SDLContext::SDLContext() { int img_flags = IMG_INIT_PNG; if (!(IMG_Init(img_flags) & img_flags)) { - // FIXME: throw exception - std::cout << "SDL_image could not initialize! SDL_image Error: " << IMG_GetError() - << std::endl; + throw std::runtime_error("SDL_image could not initialize!"); } } @@ -103,40 +96,64 @@ void SDLContext::handle_events(bool & running) { 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)); - - 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 = { +SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const { + return SDL_Rect{ .x = sprite.sprite_rect.x, .y = sprite.sprite_rect.y, .w = sprite.sprite_rect.w, .h = sprite.sprite_rect.h, }; +} +SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const Vector2 & pos, + const double & scale, const Camera & cam) const { + + double adjusted_x = (pos.x - cam.x) * cam.zoom; + double adjusted_y = (pos.y - cam.y) * cam.zoom; + double adjusted_w = sprite.sprite_rect.w * scale * cam.zoom; + double adjusted_h = sprite.sprite_rect.h * scale * cam.zoom; - SDL_Rect dstrect = { + return SDL_Rect{ .x = static_cast<int>(adjusted_x), .y = static_cast<int>(adjusted_y), .w = static_cast<int>(adjusted_w), .h = static_cast<int>(adjusted_h), }; +} + +void SDLContext::draw_particle(const Sprite & sprite, const Vector2 & pos, + const double & angle, const double & scale, + const Camera & camera) const { + + SDL_RendererFlip render_flip + = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) + | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); + + SDL_Rect srcrect = this->get_src_rect(sprite); + SDL_Rect dstrect = this->get_dst_rect(sprite, pos, scale, camera); + + SDL_RenderCopyEx(this->game_renderer.get(), sprite.sprite_image->texture.get(), &srcrect, + &dstrect, angle, NULL, render_flip); +} + +void SDLContext::draw(const Sprite & sprite, const Transform & transform, + const Camera & cam) const { + + SDL_RendererFlip render_flip + = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) + | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); + + SDL_Rect srcrect = this->get_src_rect(sprite); + SDL_Rect dstrect = this->get_dst_rect(sprite, transform.position, transform.scale, cam); SDL_RenderCopyEx(this->game_renderer.get(), sprite.sprite_image->texture.get(), &srcrect, &dstrect, transform.rotation, NULL, render_flip); } -void SDLContext::camera(const Camera & cam) { +void SDLContext::set_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); + this->viewport.x = static_cast<int>(cam.x) - (this->viewport.w / 2); + this->viewport.y = static_cast<int>(cam.y) - (this->viewport.h / 2); SDL_SetRenderDrawColor(this->game_renderer.get(), cam.bg_color.r, cam.bg_color.g, cam.bg_color.b, cam.bg_color.a); @@ -150,6 +167,7 @@ SDLContext::texture_from_path(const std::string & path) { SDL_Surface * tmp = IMG_Load(path.c_str()); if (tmp == nullptr) { tmp = IMG_Load("../asset/texture/ERROR.png"); + if (tmp == nullptr) throw runtime_error("cannot load image"); } std::unique_ptr<SDL_Surface, std::function<void(SDL_Surface *)>> img_surface; diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 652a83e..9a514cb 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -1,8 +1,10 @@ #pragma once #include <SDL2/SDL_keycode.h> +#include <SDL2/SDL_rect.h> #include <SDL2/SDL_render.h> #include <SDL2/SDL_video.h> +#include <cmath> #include <functional> #include <memory> #include <string> @@ -10,10 +12,7 @@ #include "../api/Sprite.h" #include "../api/Transform.h" #include "api/Camera.h" - -// FIXME: this needs to be removed -const int SCREEN_WIDTH = 640; -const int SCREEN_HEIGHT = 480; +#include "api/Vector2.h" namespace crepe { @@ -119,7 +118,10 @@ private: * \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); + void draw(const Sprite & sprite, const Transform & transform, const Camera & camera) const; + + void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, + const double & scale, const Camera & camera) const; //! Clears the screen, preparing for a new frame. void clear_screen(); @@ -128,10 +130,31 @@ private: void present_screen(); /** - * \brief Sets the current camera for rendering. + * \brief sets the background of the camera (will be adjusted in future PR) * \param camera Reference to the Camera object. */ - void camera(const Camera & camera); + void set_camera(const Camera & camera); + +private: + /** + * \brief calculates the sqaure size of the image + * + * \param sprite Reference to the sprite to calculate the rectangle + * \return sdl rectangle to draw a src image + */ + SDL_Rect get_src_rect(const Sprite & sprite) const; + /** + * \brief calculates the sqaure size of the image for an destination + * + * \param sprite Reference to the sprite to calculate the rectangle + * \param pos the pos in pixel positions + * \param scale the multiplier to increase of decrease for the specified sprite + * \param cam Reference to the current camera in the scene to calculate the position based + * on the camera + * \return sdl rectangle to draw a dst image to draw on the screen + */ + SDL_Rect get_dst_rect(const Sprite & sprite, const Vector2 & pos, const double & scale, + const Camera & cam) const; private: //! sdl Window diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 96c5f27..bc5422d 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -1,12 +1,14 @@ #include <algorithm> #include <cassert> -#include <functional> +#include <cmath> #include <stdexcept> #include <vector> #include "../ComponentManager.h" +#include "../api/ParticleEmitter.h" #include "../api/Sprite.h" #include "../api/Transform.h" +#include "../api/Vector2.h" #include "../facade/SDLContext.h" #include "RenderSystem.h" @@ -25,7 +27,7 @@ void RenderSystem::update_camera() { if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene"); for (Camera & cam : cameras) { - this->context.camera(cam); + this->context.set_camera(cam); this->curr_cam_ref = &cam; } } @@ -46,20 +48,58 @@ RenderSystem::sort(std::vector<std::reference_wrapper<Sprite>> & objs) { return sorted_objs; } -void RenderSystem::render_sprites() { - ComponentManager & mgr = this->component_manager; - vector<reference_wrapper<Sprite>> sprites = mgr.get_components_by_type<Sprite>(); - vector<reference_wrapper<Sprite>> sorted_sprites = this->sort(sprites); - for (const Sprite & sprite : sorted_sprites) { - auto transforms = mgr.get_components_by_id<Transform>(sprite.game_object_id); - this->context.draw(sprite, transforms[0], *this->curr_cam_ref); - } -} void RenderSystem::update() { this->clear_screen(); this->update_camera(); - this->render_sprites(); + this->render(); this->present_screen(); } + +bool RenderSystem::render_particle(const Sprite & sprite, const double & scale) const { + + ComponentManager & mgr = this->component_manager; + + auto emitters = mgr.get_components_by_id<ParticleEmitter>(sprite.game_object_id); + + bool rendering_particles = false; + + for (const ParticleEmitter & em : emitters) { + if (!(&em.data.sprite == &sprite)) continue; + rendering_particles = true; + if (!em.active) continue; + + + for (const Particle & p : em.data.particles) { + if (!p.active) continue; + this->context.draw_particle(sprite, p.position, p.angle, scale, *this->curr_cam); + } + } + return rendering_particles; +} +void RenderSystem::render_normal(const Sprite & sprite, const Transform & tm) const { + + ComponentManager & mgr = this->component_manager; + + this->context.draw(sprite, tm, *this->curr_cam); +} + +void RenderSystem::render() const { + + ComponentManager & mgr = this->component_manager; + vector<reference_wrapper<Sprite>> sprites = mgr.get_components_by_type<Sprite>(); + vector<reference_wrapper<Sprite>> sorted_sprites = this->sort(sprites); + + for (const Sprite & sprite : sorted_sprites) { + if (!sprite.active) continue; + const Transform & transform + = mgr.get_components_by_id<Transform>(sprite.game_object_id).front().get(); + + bool rendered_particles = this->render_particle(sprite, transform.scale); + + if (rendered_particles) continue; + + this->render_normal(sprite, transform); + } +} diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 57b9c73..b9033fb 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -6,6 +6,7 @@ #include "facade/SDLContext.h" #include "System.h" +#include <cmath> namespace crepe { @@ -27,7 +28,7 @@ public: * This method is called to perform all rendering operations for the current game frame. */ void update() override; - + private: //! Clears the screen in preparation for rendering. void clear_screen(); @@ -38,8 +39,25 @@ private: //! Updates the active camera used for rendering. void update_camera(); - //! Renders all active sprites to the screen. - void render_sprites(); + //! Renders the whole screen + void render() const; + + /** + * \brief Renders all the particles on the screen from a given sprite. + * + * \param sprite renders the particles with given texture + * \param tm the Transform component for scale + * \return true if particles have been rendered + */ + bool render_particle(const Sprite & sprite, const double & scale) const; + + /** + * \brief renders a sprite with a Transform component on the screen + * + * \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 Transform & tm); /** * \brief sort a vector sprite objects with @@ -52,7 +70,6 @@ private: /** * \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. diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 3a5b543..ec08c08 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -29,5 +29,6 @@ add_example(db) add_example(ecs) add_example(scene_manager) add_example(particles) +add_example(rendering_particle) add_example(gameloop) diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp new file mode 100644 index 0000000..bcf95b8 --- /dev/null +++ b/src/example/rendering_particle.cpp @@ -0,0 +1,64 @@ +#include "api/Camera.h" +#include "system/ParticleSystem.h" +#include <SDL2/SDL_timer.h> +#include <crepe/ComponentManager.h> + +#include <crepe/Component.h> +#include <crepe/api/Color.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/ParticleEmitter.h> +#include <crepe/api/Rigidbody.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Texture.h> +#include <crepe/api/Transform.h> +#include <crepe/api/Vector2.h> +#include <crepe/system/RenderSystem.h> + +#include <chrono> +#include <memory> + +using namespace crepe; +using namespace std; + +int main(int argc, char * argv[]) { + ComponentManager mgr; + GameObject game_object = mgr.new_object("", "", Vector2{100, 100}, 0, 0.1); + RenderSystem sys{mgr}; + ParticleSystem psys{mgr}; + + Color color(255, 255, 255, 255); + game_object.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{false,false}); + + Sprite test_sprite = game_object.add_component<Sprite>( + make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{false, false}); + game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ + .position = {100, 0}, + .max_particles = 10, + .emission_rate = 0.1, + .min_speed = 6, + .max_speed = 20, + .min_angle = -20, + .max_angle = 20, + .begin_lifespan = 0, + .end_lifespan = 60, + .force_over_time = Vector2{0, 0}, + .boundary{ + .width = 1000, + .height = 1000, + .offset = Vector2{0, 0}, + .reset_on_exit = false, + }, + .sprite = test_sprite, + }).active = false; + game_object.add_component<Camera>(Color::get_white()); + + + auto start = std::chrono::steady_clock::now(); + while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { + psys.update(); + sys.update(); + SDL_Delay(10); + } + + return 0; +} |