Переглянути джерело

first draft of the engine

main
Ludovic 'Archivist' Lagouardette 11 місяці тому
коміт
e2e7489253
22 змінених файлів з 468 додано та 0 видалено
  1. +1
    -0
      .gitignore
  2. +8
    -0
      .idea/.gitignore
  3. +4
    -0
      .idea/misc.xml
  4. +8
    -0
      .idea/modules.xml
  5. +6
    -0
      .idea/vcs.xml
  6. +7
    -0
      CMakeLists.txt
  7. +27
    -0
      Engine/CMakeLists.txt
  8. BIN
      Engine/assets/apple.png
  9. +19
    -0
      Engine/include/component.h
  10. +19
    -0
      Engine/include/components/sprite_component.h
  11. +18
    -0
      Engine/include/entities/background_entity.h
  12. +14
    -0
      Engine/include/entities/ui_fps_entity.h
  13. +139
    -0
      Engine/include/entity.h
  14. +16
    -0
      Engine/include/render_state.h
  15. +24
    -0
      Engine/include/scene.h
  16. +27
    -0
      Engine/include/transform.h
  17. +7
    -0
      Engine/src/background_entity.cpp
  18. +39
    -0
      Engine/src/main.cpp
  19. +31
    -0
      Engine/src/render_state.cpp
  20. +3
    -0
      Engine/src/scene.cpp
  21. +41
    -0
      Engine/src/sprite_component.cpp
  22. +10
    -0
      Engine/src/ui_fps_entity.cpp

+ 1
- 0
.gitignore Переглянути файл

@ -0,0 +1 @@
cmake-build-*/

+ 8
- 0
.idea/.gitignore Переглянути файл

@ -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

+ 4
- 0
.idea/misc.xml Переглянути файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

+ 8
- 0
.idea/modules.xml Переглянути файл

@ -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>

+ 6
- 0
.idea/vcs.xml Переглянути файл

@ -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>

+ 7
- 0
CMakeLists.txt Переглянути файл

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

+ 27
- 0
Engine/CMakeLists.txt Переглянути файл

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

BIN
Engine/assets/apple.png Переглянути файл

Перед Після
Ширина: 560  |  Висота: 640  |  Розмір: 49 KiB

+ 19
- 0
Engine/include/component.h Переглянути файл

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

+ 19
- 0
Engine/include/components/sprite_component.h Переглянути файл

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

+ 18
- 0
Engine/include/entities/background_entity.h Переглянути файл

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

+ 14
- 0
Engine/include/entities/ui_fps_entity.h Переглянути файл

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

+ 139
- 0
Engine/include/entity.h Переглянути файл

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

+ 16
- 0
Engine/include/render_state.h Переглянути файл

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

+ 24
- 0
Engine/include/scene.h Переглянути файл

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

+ 27
- 0
Engine/include/transform.h Переглянути файл

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

+ 7
- 0
Engine/src/background_entity.cpp Переглянути файл

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

+ 39
- 0
Engine/src/main.cpp Переглянути файл

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

+ 31
- 0
Engine/src/render_state.cpp Переглянути файл

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

+ 3
- 0
Engine/src/scene.cpp Переглянути файл

@ -0,0 +1,3 @@
#include "scene.h"
std::shared_ptr<ant::core::scene> ant::core::scene::current;

+ 41
- 0
Engine/src/sprite_component.cpp Переглянути файл

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

+ 10
- 0
Engine/src/ui_fps_entity.cpp Переглянути файл

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

Завантаження…
Відмінити
Зберегти