| @ -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)); | |||
| }); | |||
| } | |||