| @ -0,0 +1 @@ | |||||
| cmake-build-*/ | |||||
| @ -0,0 +1,8 @@ | |||||
| # Default ignored files | |||||
| /shelf/ | |||||
| /workspace.xml | |||||
| # Editor-based HTTP Client requests | |||||
| /httpRequests/ | |||||
| # Datasource local storage ignored files | |||||
| /dataSources/ | |||||
| /dataSources.local.xml | |||||
| @ -0,0 +1,4 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" /> | |||||
| </project> | |||||
| @ -0,0 +1,8 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="ProjectModuleManager"> | |||||
| <modules> | |||||
| <module fileurl="file://$PROJECT_DIR$/.idea/ProcurementOS.iml" filepath="$PROJECT_DIR$/.idea/ProcurementOS.iml" /> | |||||
| </modules> | |||||
| </component> | |||||
| </project> | |||||
| @ -0,0 +1,6 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="VcsDirectoryMappings"> | |||||
| <mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/raylib-src" vcs="Git" /> | |||||
| </component> | |||||
| </project> | |||||
| @ -0,0 +1,7 @@ | |||||
| cmake_minimum_required(VERSION 3.24) | |||||
| project(Ant) | |||||
| set(CMAKE_VERBOSE_MAKEFILE ON) | |||||
| set(CMAKE_CXX_STANDARD 23) | |||||
| add_subdirectory(Engine) | |||||
| @ -0,0 +1,27 @@ | |||||
| Include(FetchContent) | |||||
| FetchContent_Declare( | |||||
| RayLib | |||||
| GIT_REPOSITORY D:/AntiJeu/cmake-build-debug/_deps/raylib-src | |||||
| GIT_TAG 4.5.0 | |||||
| GIT_PROGRESS TRUE | |||||
| ) | |||||
| FetchContent_MakeAvailable(RayLib) | |||||
| add_executable(Engine | |||||
| src/main.cpp | |||||
| include/entity.h | |||||
| include/transform.h | |||||
| include/component.h | |||||
| include/scene.h | |||||
| include/render_state.h | |||||
| src/render_state.cpp | |||||
| src/scene.cpp | |||||
| include/entities/ui_fps_entity.h | |||||
| src/ui_fps_entity.cpp | |||||
| include/entities/background_entity.h | |||||
| src/background_entity.cpp | |||||
| include/components/sprite_component.h src/sprite_component.cpp) | |||||
| target_include_directories(Engine PUBLIC include) | |||||
| target_link_libraries(Engine PUBLIC raylib) | |||||
| file(COPY assets/apple.png DESTINATION assets/apple.png) | |||||
| @ -0,0 +1,19 @@ | |||||
| #pragma once | |||||
| #include <chrono> | |||||
| namespace ant::core { | |||||
| struct entity; | |||||
| struct component { | |||||
| virtual std::string name() = 0; | |||||
| virtual void initialize() {} | |||||
| virtual void render() {} | |||||
| virtual void update(std::chrono::duration<double>) {} | |||||
| [[nodiscard]] auto owner() -> std::shared_ptr<entity> { | |||||
| return m_owner.lock(); | |||||
| } | |||||
| private: | |||||
| std::weak_ptr<entity> m_owner; | |||||
| friend struct entity; | |||||
| }; | |||||
| } | |||||
| @ -0,0 +1,19 @@ | |||||
| #pragma once | |||||
| #include "component.h" | |||||
| #include <string> | |||||
| #include "raylib.h" | |||||
| #include "transform.h" | |||||
| namespace ant::components::graphical { | |||||
| struct sprite_component : public ant::core::component { | |||||
| sprite_component() {} | |||||
| sprite_component(const std::string& str, int layer = 0, ant::core::transform<> reposition = {{0,0},0}, ant::core::Vec2<> scale = {1,1}); | |||||
| std::string name() override {return "sprite_component";} | |||||
| void render() override; | |||||
| private: | |||||
| Texture2D current_texture; | |||||
| ant::core::transform<> transform; | |||||
| ant::core::Vec2<> m_scale; | |||||
| int m_layer; | |||||
| }; | |||||
| } | |||||
| @ -0,0 +1,18 @@ | |||||
| #pragma once | |||||
| #include "entity.h" | |||||
| #include "raylib.h" | |||||
| namespace ant::entities::utilities { | |||||
| struct background_entity : public ant::core::entity { | |||||
| background_entity(const std::shared_ptr<entity>& parent, Color color) | |||||
| : ant::core::entity(parent) | |||||
| , m_color(color) | |||||
| {} | |||||
| void render() final; | |||||
| private: | |||||
| Color m_color; | |||||
| }; | |||||
| } | |||||
| @ -0,0 +1,14 @@ | |||||
| #pragma once | |||||
| #include "entity.h" | |||||
| namespace ant::entities::utilities { | |||||
| struct ui_fps_entity : public ant::core::entity { | |||||
| ui_fps_entity(const std::shared_ptr<entity>& parent) | |||||
| : ant::core::entity(parent) | |||||
| {} | |||||
| void render() final; | |||||
| }; | |||||
| } | |||||
| @ -0,0 +1,139 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <vector> | |||||
| #include <chrono> | |||||
| #include <utility> | |||||
| #include <ranges> | |||||
| #include "transform.h" | |||||
| #include "component.h" | |||||
| namespace ant::core { | |||||
| struct entity { | |||||
| [[nodiscard]] auto transform() const -> ant::core::transform<float> { | |||||
| return m_transform; | |||||
| } | |||||
| auto transform() -> ant::core::transform<float>& { | |||||
| return m_transform; | |||||
| } | |||||
| [[nodiscard]] auto world_transform() const -> ant::core::transform<float> { | |||||
| ant::core::transform<float> ret{{0,0},0}; | |||||
| if(auto parent = m_parent.lock(); parent) { | |||||
| ret = parent->world_transform(); | |||||
| } | |||||
| auto transform_pivot = transform(); | |||||
| if(ret.angle != 0.0f) { | |||||
| transform_pivot.position.X *= std::cos(ret.angle*std::numbers::pi/180); | |||||
| transform_pivot.position.Y *= std::sin(ret.angle*std::numbers::pi/180); | |||||
| } | |||||
| return ret + transform_pivot; | |||||
| } | |||||
| [[nodiscard]] auto parent() const -> std::shared_ptr<entity> { | |||||
| return m_parent.lock(); | |||||
| } | |||||
| [[nodiscard]] auto is_visible() const -> bool { | |||||
| if(auto parent = m_parent.lock(); parent){ | |||||
| if(not parent->is_visible()) { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| return m_is_visible; | |||||
| } | |||||
| [[nodiscard]] auto visibility_flag() const -> bool { | |||||
| return m_is_visible; | |||||
| } | |||||
| [[nodiscard]] auto find_components(std::string name) const -> std::vector<std::shared_ptr<component>> { | |||||
| decltype(m_components) ret; | |||||
| auto source = m_components | std::views::filter([&](const auto& elem) {return name == elem->name();}); | |||||
| std::ranges::copy(source, std::back_inserter(ret)); | |||||
| return ret; | |||||
| } | |||||
| [[nodiscard]] auto components_list() const -> const std::vector<std::shared_ptr<component>>& { | |||||
| return m_components; | |||||
| } | |||||
| [[nodiscard]] auto components_list() -> std::vector<std::shared_ptr<component>>& { | |||||
| return m_components; | |||||
| } | |||||
| template<std::derived_from<component> ComponentType, typename... ARGS> | |||||
| auto add_component(ARGS&&... constructor_args) -> std::shared_ptr<entity> { | |||||
| auto component = std::make_shared<ComponentType>(std::forward<ARGS>(constructor_args)...); | |||||
| auto self = m_self.lock(); | |||||
| component->m_owner = self; | |||||
| m_components.push_back(component); | |||||
| component->initialize(); | |||||
| return self; | |||||
| } | |||||
| auto set_visible(bool visible) -> bool { | |||||
| return std::exchange(m_is_visible, visible); | |||||
| } | |||||
| virtual void initialize() {} | |||||
| virtual void render() { | |||||
| if(not visibility_flag()) return; | |||||
| for(auto& child : m_children | std::views::filter([](const std::shared_ptr<entity>& elem){return elem->visibility_flag();})) { | |||||
| child->render(); | |||||
| } | |||||
| for(auto& component : m_components) { | |||||
| component->render(); | |||||
| } | |||||
| } | |||||
| virtual void update(std::chrono::duration<double> delta_time) { | |||||
| for(auto& child : m_children) { | |||||
| child->update(delta_time); | |||||
| } | |||||
| for(auto& component : m_components) { | |||||
| component->update(delta_time); | |||||
| } | |||||
| } | |||||
| entity(const std::shared_ptr<entity>& parent) | |||||
| : m_is_visible(true) | |||||
| , m_parent(parent) | |||||
| , m_children() | |||||
| , m_components() | |||||
| , m_transform{.position = {0,0}, .angle = 0} | |||||
| {} | |||||
| entity() | |||||
| : m_is_visible(true) | |||||
| , m_parent(std::shared_ptr<entity>(nullptr)) | |||||
| , m_children() | |||||
| , m_components() | |||||
| , m_transform{.position = {0,0}, .angle = 0} | |||||
| {} | |||||
| private: | |||||
| bool m_is_visible; | |||||
| std::weak_ptr<entity> m_parent; | |||||
| std::weak_ptr<entity> m_self; | |||||
| std::vector<std::shared_ptr<entity>> m_children; | |||||
| std::vector<std::shared_ptr<component>> m_components; | |||||
| ant::core::transform<float> m_transform; | |||||
| template<std::derived_from<entity> EntityType> | |||||
| friend auto make_entity(const std::shared_ptr<entity>& parent, auto&&... ARGS) -> std::shared_ptr<EntityType>; | |||||
| template<std::derived_from<entity> EntityType> | |||||
| friend auto make_entity(auto&&... ARGS) -> std::shared_ptr<EntityType>; | |||||
| }; | |||||
| template<std::derived_from<entity> EntityType> | |||||
| [[nodiscard]] auto make_entity(const std::shared_ptr<entity>& parent, auto&&... ARGS) -> std::shared_ptr<EntityType> { | |||||
| auto object = std::make_shared<EntityType>(std::forward<decltype(ARGS)>(ARGS)...); | |||||
| const std::shared_ptr<entity>& entity_router = object; | |||||
| entity_router->m_parent = parent; | |||||
| entity_router->m_self = object; | |||||
| if(parent) { | |||||
| parent->m_children.push_back(object); | |||||
| } | |||||
| object->initialize(); | |||||
| return object; | |||||
| } | |||||
| template<std::derived_from<entity> EntityType> | |||||
| [[nodiscard]] auto make_entity(auto&&... ARGS) -> std::shared_ptr<EntityType> { | |||||
| auto object = std::make_shared<EntityType>(std::shared_ptr<entity>(nullptr), std::forward<decltype(ARGS)>(ARGS)...); | |||||
| const std::shared_ptr<entity>& entity_router = object; | |||||
| entity_router->m_parent = std::shared_ptr<entity>(nullptr); | |||||
| entity_router->m_self = object; | |||||
| object->initialize(); | |||||
| return object; | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,16 @@ | |||||
| #pragma once | |||||
| #include <functional> | |||||
| namespace ant::render { | |||||
| enum class layer_pos { | |||||
| start, | |||||
| any, | |||||
| end | |||||
| }; | |||||
| void schedule_in_frame(int layer, std::function<void()> fn, layer_pos pos = layer_pos::any); | |||||
| void schedule_in_frame(int layer, auto fn, layer_pos pos = layer_pos::any) { | |||||
| schedule_in_frame(layer, std::function<void()>{std::move(fn)}, pos); | |||||
| } | |||||
| void render_all(); | |||||
| } | |||||
| @ -0,0 +1,24 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <vector> | |||||
| #include <chrono> | |||||
| #include "entity.h" | |||||
| namespace ant::core { | |||||
| struct scene { | |||||
| static std::shared_ptr<scene> current; | |||||
| std::vector<std::shared_ptr<entity>> root_nodes; | |||||
| void update(std::chrono::duration<double> delta_time) { | |||||
| for (auto &elem: root_nodes) { | |||||
| elem->update(delta_time); | |||||
| } | |||||
| } | |||||
| void render() { | |||||
| for (auto &elem: root_nodes | std::views::filter([](const std::shared_ptr<entity>& elem){return elem->visibility_flag();})) { | |||||
| elem->render(); | |||||
| } | |||||
| } | |||||
| }; | |||||
| } | |||||
| @ -0,0 +1,27 @@ | |||||
| #pragma once | |||||
| #include <cmath> | |||||
| #include <numbers> | |||||
| namespace ant::core { | |||||
| template<typename T = float> | |||||
| struct Vec2 { | |||||
| T X; | |||||
| T Y; | |||||
| }; | |||||
| template<typename T> | |||||
| auto operator+(const Vec2<T>& lhs, const Vec2<T>& rhs) -> Vec2<T>{ | |||||
| return {.X = lhs.X + rhs.X, .Y = lhs.Y + rhs.Y}; | |||||
| } | |||||
| template<typename T = float> | |||||
| struct transform { | |||||
| Vec2<T> position; | |||||
| float angle; | |||||
| }; | |||||
| template<typename T> | |||||
| auto operator+(const transform<T>& lhs, const transform<T>& rhs) -> transform<T>{ | |||||
| return {.position = lhs.position + rhs.position, .angle = std::fmod<float>(lhs.angle + rhs.angle, 180.0f)}; | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,7 @@ | |||||
| #include "entities/background_entity.h" | |||||
| #include "render_state.h" | |||||
| #include "raylib.h" | |||||
| void ant::entities::utilities::background_entity::render() { | |||||
| ant::render::schedule_in_frame(-255, [color = m_color](){ ClearBackground(color);}); | |||||
| } | |||||
| @ -0,0 +1,39 @@ | |||||
| #include "raylib.h" | |||||
| #include "scene.h" | |||||
| #include "render_state.h" | |||||
| #include "entities/ui_fps_entity.h" | |||||
| #include "entities/background_entity.h" | |||||
| #include "components/sprite_component.h" | |||||
| using namespace std::string_literals; | |||||
| int main() { | |||||
| InitWindow(800, 600, "Example"); | |||||
| ant::core::scene::current = std::make_shared<ant::core::scene>(); | |||||
| ant::core::scene::current->root_nodes.push_back(ant::core::make_entity<ant::entities::utilities::ui_fps_entity>()); | |||||
| ant::core::scene::current->root_nodes.push_back(ant::core::make_entity<ant::core::entity>()); | |||||
| ant::core::scene::current->root_nodes.back() | |||||
| ->add_component<ant::components::graphical::sprite_component>( | |||||
| "Engine/assets/apple.png"s, | |||||
| 0, | |||||
| ant::core::transform<>{{560/2, 640/2}, 60}, | |||||
| ant::core::Vec2<>{0.5,0.5} | |||||
| ); | |||||
| ant::core::scene::current->root_nodes.back()->transform().position = {250,250}; | |||||
| ant::core::scene::current->root_nodes.back()->transform().angle = 120; | |||||
| ant::core::scene::current->root_nodes.push_back(ant::core::make_entity<ant::entities::utilities::background_entity>(BLACK)); | |||||
| auto ref = std::chrono::steady_clock::now(); | |||||
| std::chrono::duration<double> frame_time = ref - ref; | |||||
| while(not WindowShouldClose()) { | |||||
| ant::core::scene::current->update(frame_time); | |||||
| ant::core::scene::current->render(); | |||||
| BeginDrawing(); | |||||
| ant::render::render_all(); | |||||
| EndDrawing(); | |||||
| auto new_time = std::chrono::steady_clock::now(); | |||||
| frame_time = new_time - ref; | |||||
| ref = new_time; | |||||
| } | |||||
| CloseWindow(); | |||||
| return 0; | |||||
| } | |||||
| @ -0,0 +1,31 @@ | |||||
| #include <queue> | |||||
| #include "render_state.h" | |||||
| struct render_thunk { | |||||
| int prio; | |||||
| ant::render::layer_pos pos = ant::render::layer_pos::any; | |||||
| std::function<void()> op; | |||||
| }; | |||||
| static bool operator<(const render_thunk& lhs, const render_thunk& rhs) { | |||||
| if(lhs.prio < rhs.prio) { | |||||
| if(lhs.pos > rhs.pos) { | |||||
| return false; | |||||
| } else { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static std::priority_queue<render_thunk> renders; | |||||
| void ant::render::schedule_in_frame(int layer, std::function<void()> fn, ant::render::layer_pos pos) { | |||||
| renders.push({layer, pos, std::move(fn)}); | |||||
| } | |||||
| void ant::render::render_all() { | |||||
| while(not renders.empty()) { | |||||
| renders.top().op(); | |||||
| renders.pop(); | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,3 @@ | |||||
| #include "scene.h" | |||||
| std::shared_ptr<ant::core::scene> ant::core::scene::current; | |||||
| @ -0,0 +1,41 @@ | |||||
| #include "components/sprite_component.h" | |||||
| #include "entity.h" | |||||
| #include "render_state.h" | |||||
| ant::components::graphical::sprite_component::sprite_component(const std::string& str, int layer, ant::core::transform<> reposition, ant::core::Vec2<> scale) | |||||
| // TODO: Textures should be managed by an asset manager | |||||
| : current_texture(LoadTexture(str.c_str())) | |||||
| , transform(reposition) | |||||
| , m_scale(scale) | |||||
| , m_layer(layer) | |||||
| {} | |||||
| void ant::components::graphical::sprite_component::render() { | |||||
| Rectangle source = { | |||||
| .x = 0, | |||||
| .y = 0, | |||||
| .width = static_cast<float>(current_texture.width), | |||||
| .height = static_cast<float>(current_texture.height) | |||||
| }; | |||||
| auto draw_position = owner()->world_transform(); | |||||
| draw_position = draw_position + transform; | |||||
| Rectangle dest = { | |||||
| .x = draw_position.position.X-transform.position.X, | |||||
| .y = draw_position.position.Y-transform.position.Y, | |||||
| .width = static_cast<float>(current_texture.width) * m_scale.X, | |||||
| .height = static_cast<float>(current_texture.height) * m_scale.Y | |||||
| }; | |||||
| ant::render::schedule_in_frame(m_layer, [current_texture = this->current_texture, dest, transform = this->transform, source, draw_position, m_scale = this->m_scale](){ | |||||
| DrawTexturePro( | |||||
| current_texture, | |||||
| source, | |||||
| dest, | |||||
| Vector2{ | |||||
| transform.position.X * m_scale.X, | |||||
| transform.position.Y * m_scale.Y | |||||
| }, | |||||
| draw_position.angle, | |||||
| WHITE | |||||
| ); | |||||
| }); | |||||
| } | |||||
| @ -0,0 +1,10 @@ | |||||
| #include "entities/ui_fps_entity.h" | |||||
| #include "render_state.h" | |||||
| #include "raylib.h" | |||||
| void ant::entities::utilities::ui_fps_entity::render() { | |||||
| entity::render(); | |||||
| ant::render::schedule_in_frame(255, [coords = this->transform().position](){ | |||||
| DrawFPS(static_cast<int>(coords.X),static_cast<int>(coords.Y)); | |||||
| }); | |||||
| } | |||||