aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mwe/events/include/event.h2
-rw-r--r--src/crepe/api/Color.h4
-rw-r--r--src/crepe/api/Sprite.h3
-rw-r--r--src/crepe/facade/SDLContext.h6
-rw-r--r--src/crepe/system/RenderSystem.cpp43
-rw-r--r--src/crepe/system/RenderSystem.h26
-rw-r--r--src/example/rendering.cpp25
-rw-r--r--src/test/CMakeLists.txt1
-rw-r--r--src/test/rendering.cpp174
9 files changed, 251 insertions, 33 deletions
diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h
index ee1bf52..e1b220b 100644
--- a/mwe/events/include/event.h
+++ b/mwe/events/include/event.h
@@ -148,7 +148,7 @@ private:
};
class ShutDownEvent : public Event {
public:
- ShutDownEvent() : Event("ShutDownEvent") {};
+ ShutDownEvent() : Event("ShutDownEvent"){};
REGISTER_EVENT_TYPE(ShutDownEvent)
diff --git a/src/crepe/api/Color.h b/src/crepe/api/Color.h
index aa47bf4..c207ba7 100644
--- a/src/crepe/api/Color.h
+++ b/src/crepe/api/Color.h
@@ -21,13 +21,13 @@ public:
static const Color & get_yellow();
static const Color & get_black();
-private:
- // TODO: why are these private!?
+public:
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
+private:
static Color white;
static Color red;
static Color green;
diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h
index 0192793..74a55d4 100644
--- a/src/crepe/api/Sprite.h
+++ b/src/crepe/api/Sprite.h
@@ -2,8 +2,9 @@
#include <memory>
+#include "../Component.h"
+
#include "Color.h"
-#include "Component.h"
#include "Texture.h"
namespace crepe {
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index 007092b..652a83e 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -21,9 +21,6 @@ namespace crepe {
// 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
@@ -91,9 +88,6 @@ private:
//! Will use the funtions: texture_from_path, get_width,get_height.
friend class Texture;
- //! 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.
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index fa3d0de..96c5f27 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -1,38 +1,59 @@
+#include <algorithm>
+#include <cassert>
#include <functional>
+#include <stdexcept>
#include <vector>
#include "../ComponentManager.h"
#include "../api/Sprite.h"
#include "../api/Transform.h"
#include "../facade/SDLContext.h"
-#include "../util/Log.h"
#include "RenderSystem.h"
using namespace crepe;
+using namespace std;
-void RenderSystem::clear_screen() const { SDLContext::get_instance().clear_screen(); }
+void RenderSystem::clear_screen() { this->context.clear_screen(); }
-void RenderSystem::present_screen() const { SDLContext::get_instance().present_screen(); }
+void RenderSystem::present_screen() { this->context.present_screen(); }
void RenderSystem::update_camera() {
ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<Camera>> cameras = mgr.get_components_by_type<Camera>();
+ if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene");
+
for (Camera & cam : cameras) {
- SDLContext::get_instance().camera(cam);
- this->curr_cam = &cam;
+ this->context.camera(cam);
+ this->curr_cam_ref = &cam;
}
}
-void RenderSystem::render_sprites() const {
- ComponentManager & mgr = this->component_manager;
- std::vector<std::reference_wrapper<Sprite>> sprites = mgr.get_components_by_type<Sprite>();
+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;
+
+ return false;
+}
+
+std::vector<std::reference_wrapper<Sprite>>
+RenderSystem::sort(std::vector<std::reference_wrapper<Sprite>> & objs) {
+
+ std::vector<std::reference_wrapper<Sprite>> sorted_objs(objs);
+ std::sort(sorted_objs.begin(), sorted_objs.end(), sorting_comparison);
+
+ 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);
- SDLContext & render = SDLContext::get_instance();
- for (const Sprite & sprite : sprites) {
+ for (const Sprite & sprite : sorted_sprites) {
auto transforms = mgr.get_components_by_id<Transform>(sprite.game_object_id);
- render.draw(sprite, transforms[0], *curr_cam);
+ this->context.draw(sprite, transforms[0], *this->curr_cam_ref);
}
}
diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h
index 87ec494..8914b96 100644
--- a/src/crepe/system/RenderSystem.h
+++ b/src/crepe/system/RenderSystem.h
@@ -1,18 +1,23 @@
#pragma once
-#include "api/Camera.h"
+#include <functional>
+#include <vector>
+
+#include "facade/SDLContext.h"
#include "System.h"
namespace crepe {
+class Camera;
+class Sprite;
+
/**
* \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.
+ * RenderSystem is responsible for rendering, clearing and presenting the screen, and
+ * managing the active camera.
*/
class RenderSystem : public System {
public:
@@ -25,16 +30,19 @@ public:
private:
//! Clears the screen in preparation for rendering.
- void clear_screen() const;
+ void clear_screen();
//! Presents the rendered frame to the display.
- void present_screen() const;
+ void present_screen();
//! Updates the active camera used for rendering.
void update_camera();
//! Renders all active sprites to the screen.
- void render_sprites() const;
+ void render_sprites();
+
+ std::vector<std::reference_wrapper<Sprite>>
+ sort(std::vector<std::reference_wrapper<Sprite>> & objs);
/**
* \todo Include color handling for sprites.
@@ -48,8 +56,10 @@ private:
private:
//! Pointer to the current active camera for rendering
- Camera * curr_cam = nullptr;
+ Camera * curr_cam_ref = nullptr;
// TODO: needs a better solution
+
+ SDLContext & context = SDLContext::get_instance();
};
} // namespace crepe
diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp
index c9e62f1..ecd3f6a 100644
--- a/src/example/rendering.cpp
+++ b/src/example/rendering.cpp
@@ -30,14 +30,27 @@ int main() {
// Normal adding components
{
Color color(0, 0, 0, 0);
- obj.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), color,
- FlipSettings{false, false});
+ Sprite & sprite
+ = obj.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"),
+ color, FlipSettings{false, false});
+ sprite.sorting_in_layer = 2;
+ sprite.order_in_layer = 1;
obj.add_component<Camera>(Color::get_red());
}
{
Color color(0, 0, 0, 0);
- obj1.add_component<Sprite>(make_shared<Texture>("../asset/texture/second.png"), color,
- FlipSettings{true, true});
+ Sprite & sprite = obj1.add_component<Sprite>(
+ make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{true, true});
+ sprite.sorting_in_layer = 2;
+ sprite.order_in_layer = 2;
+ }
+
+ {
+ Color color(0, 0, 0, 0);
+ Sprite & sprite = obj2.add_component<Sprite>(
+ make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{true, true});
+ sprite.sorting_in_layer = 1;
+ sprite.order_in_layer = 2;
}
/*
@@ -48,8 +61,12 @@ int main() {
}
*/
+ sys.update();
+ /*
+
auto start = std::chrono::steady_clock::now();
while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) {
sys.update();
}
+ */
}
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 49c8151..0969a52 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -3,5 +3,6 @@ target_sources(test_main PUBLIC
PhysicsTest.cpp
ScriptTest.cpp
ParticleTest.cpp
+ rendering.cpp
)
diff --git a/src/test/rendering.cpp b/src/test/rendering.cpp
new file mode 100644
index 0000000..4c5fb1d
--- /dev/null
+++ b/src/test/rendering.cpp
@@ -0,0 +1,174 @@
+#include "api/Camera.h"
+#include <functional>
+#include <gtest/gtest.h>
+#include <memory>
+#include <vector>
+
+#define private public
+#define protected public
+
+#include <crepe/ComponentManager.h>
+#include <crepe/api/Color.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/Sprite.h>
+#include <crepe/api/Texture.h>
+
+#include <crepe/system/RenderSystem.h>
+
+using namespace std;
+using namespace crepe;
+using namespace testing;
+
+class RenderSystemTest : public Test {
+public:
+ ComponentManager mgr{};
+ RenderSystem sys{mgr};
+ GameObject entity1 = this->mgr.new_object("name");
+ GameObject entity2 = this->mgr.new_object("name");
+ GameObject entity3 = this->mgr.new_object("name");
+ GameObject entity4 = this->mgr.new_object("name");
+
+ void SetUp() override {
+ auto & sprite1
+ = entity1.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"),
+ Color(0, 0, 0, 0), FlipSettings{false, false});
+ ASSERT_NE(sprite1.sprite_image.get(), nullptr);
+ sprite1.order_in_layer = 5;
+ sprite1.sorting_in_layer = 5;
+ EXPECT_EQ(sprite1.order_in_layer, 5);
+ EXPECT_EQ(sprite1.sorting_in_layer, 5);
+ auto & sprite2
+ = entity2.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"),
+ Color(0, 0, 0, 0), FlipSettings{false, false});
+ ASSERT_NE(sprite2.sprite_image.get(), nullptr);
+ sprite2.sorting_in_layer = 2;
+ sprite2.order_in_layer = 1;
+
+ EXPECT_EQ(sprite2.sorting_in_layer, 2);
+ EXPECT_EQ(sprite2.order_in_layer, 1);
+
+ auto & sprite3
+ = entity3.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"),
+ Color(0, 0, 0, 0), FlipSettings{false, false});
+ ASSERT_NE(sprite3.sprite_image.get(), nullptr);
+ sprite3.sorting_in_layer = 1;
+ sprite3.order_in_layer = 2;
+
+ EXPECT_EQ(sprite3.sorting_in_layer, 1);
+ EXPECT_EQ(sprite3.order_in_layer, 2);
+
+ auto & sprite4
+ = entity4.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"),
+ Color(0, 0, 0, 0), FlipSettings{false, false});
+ ASSERT_NE(sprite4.sprite_image.get(), nullptr);
+ sprite4.sorting_in_layer = 1;
+ sprite4.order_in_layer = 1;
+ EXPECT_EQ(sprite4.sorting_in_layer, 1);
+ EXPECT_EQ(sprite4.order_in_layer, 1);
+ }
+};
+
+TEST_F(RenderSystemTest, expected_throws) {
+ GameObject entity1 = this->mgr.new_object("NAME");
+
+ // no texture img
+ EXPECT_ANY_THROW({
+ entity1.add_component<Sprite>(make_shared<Texture>("NO_IMAGE"), Color(0, 0, 0, 0),
+ FlipSettings{false, false});
+ });
+
+ // No camera
+ EXPECT_ANY_THROW({ this->sys.update(); });
+}
+
+TEST_F(RenderSystemTest, make_sprites) {}
+
+TEST_F(RenderSystemTest, sorting_sprites) {
+ vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>();
+ ASSERT_EQ(sprites.size(), 4);
+
+ vector<reference_wrapper<Sprite>> sorted_sprites = this->sys.sort(sprites);
+ ASSERT_EQ(sorted_sprites.size(), 4);
+
+ // Expected order after sorting:
+ // 1. sorting_in_layer: 1, order_in_layer: 1 (entity4)
+ // 2. sorting_in_layer: 1, order_in_layer: 2 (entity3)
+ // 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[1].get().sorting_in_layer, 1);
+ EXPECT_EQ(sorted_sprites[1].get().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[3].get().sorting_in_layer, 5);
+ EXPECT_EQ(sorted_sprites[3].get().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);
+ } else {
+ EXPECT_LE(prev.sorting_in_layer, curr.sorting_in_layer);
+ }
+ }
+}
+
+TEST_F(RenderSystemTest, Update) {
+ entity1.add_component<Camera>(Color::get_white());
+ {
+ vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>();
+ ASSERT_EQ(sprites.size(), 4);
+
+ EXPECT_EQ(sprites[0].get().game_object_id, 0);
+ EXPECT_EQ(sprites[1].get().game_object_id, 1);
+ EXPECT_EQ(sprites[2].get().game_object_id, 2);
+ EXPECT_EQ(sprites[3].get().game_object_id, 3);
+ }
+ this->sys.update();
+ {
+ vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>();
+ ASSERT_EQ(sprites.size(), 4);
+
+ EXPECT_EQ(sprites[0].get().game_object_id, 0);
+ EXPECT_EQ(sprites[1].get().game_object_id, 1);
+ EXPECT_EQ(sprites[2].get().game_object_id, 2);
+ EXPECT_EQ(sprites[3].get().game_object_id, 3);
+ }
+}
+
+TEST_F(RenderSystemTest, Camera) {
+ {
+ auto cameras = this->mgr.get_components_by_type<Camera>();
+ EXPECT_NE(cameras.size(), 1);
+ }
+ {
+ entity1.add_component<Camera>(Color::get_white());
+ auto cameras = this->mgr.get_components_by_type<Camera>();
+ EXPECT_EQ(cameras.size(), 1);
+ }
+
+ //TODO improve with newer version
+}
+TEST_F(RenderSystemTest, Color) {
+ entity1.add_component<Camera>(Color::get_white());
+ auto & sprite = this->mgr.get_components_by_id<Sprite>(entity1.id).front().get();
+ ASSERT_NE(sprite.sprite_image.get(), nullptr);
+
+ sprite.color = Color::get_green();
+ EXPECT_EQ(sprite.color.r, Color::get_green().r);
+ EXPECT_EQ(sprite.color.g, Color::get_green().g);
+ EXPECT_EQ(sprite.color.b, Color::get_green().b);
+ EXPECT_EQ(sprite.color.a, Color::get_green().a);
+ this->sys.update();
+ EXPECT_EQ(sprite.color.r, Color::get_green().r);
+ EXPECT_EQ(sprite.color.g, Color::get_green().g);
+ EXPECT_EQ(sprite.color.b, Color::get_green().b);
+ EXPECT_EQ(sprite.color.a, Color::get_green().a);
+}