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