This commit is contained in:
Kbz-8
2025-06-16 15:18:27 +02:00
parent 15510fa8a7
commit cd7e5ad26f
165 changed files with 78107 additions and 0 deletions

39
Runtime/Includes/Core/CLI.h git.filemode.normal_file
View File

@@ -0,0 +1,39 @@
#ifndef __SCOP_CLI__
#define __SCOP_CLI__
#include <string>
#include <optional>
#include <unordered_map>
#include <unordered_set>
namespace Scop
{
class CommandLineInterface
{
public:
inline CommandLineInterface();
inline std::optional<std::string> GetOption(std::string_view option) const;
inline std::optional<std::string> GetArgument(std::string_view arg) const;
inline bool HasFlag(std::string_view flag) const;
inline const std::string& GetCommand() const;
inline void Feed(int ac, char** av);
inline static CommandLineInterface& Get() noexcept;
inline ~CommandLineInterface();
private:
static inline CommandLineInterface* s_instance = nullptr;
std::unordered_map<std::string, std::string> m_options;
std::unordered_set<std::string> m_flags;
std::unordered_set<std::string> m_args;
std::string m_cmd;
};
}
#include <Core/CLI.inl>
#endif

72
Runtime/Includes/Core/CLI.inl git.filemode.normal_file
View File

@@ -0,0 +1,72 @@
#pragma once
#include <Core/CLI.h>
#include <algorithm>
namespace Scop
{
CommandLineInterface::CommandLineInterface()
{
s_instance = this;
}
std::optional<std::string> CommandLineInterface::GetOption(std::string_view option) const
{
auto it = m_options.find(static_cast<std::string>(option));
if(it == m_options.end())
return std::nullopt;
return it->second;
}
std::optional<std::string> CommandLineInterface::GetArgument(std::string_view arg) const
{
auto it = std::find(m_args.begin(), m_args.end(), arg);
if(it == m_args.end())
return std::nullopt;
return *it;
}
bool CommandLineInterface::HasFlag(std::string_view flag) const
{
return std::find(m_flags.begin(), m_flags.end(), flag) != m_flags.end();
}
const std::string& CommandLineInterface::GetCommand() const
{
return m_cmd;
}
void CommandLineInterface::Feed(int ac, char** av)
{
if(ac == 0 || av == nullptr)
return;
m_cmd = av[0];
for(int i = 1; i < ac; i++)
{
std::string_view arg{ av[i] };
if(arg.front() == '-')
{
arg.remove_prefix(1);
if(arg.front() == '-') // in case of arg begenning with --
arg.remove_prefix(1);
std::size_t finder = arg.find_first_of('=');
if(finder != std::string_view::npos)
m_options.emplace(std::make_pair(arg.substr(0, finder), arg.substr(finder + 1)));
else
m_flags.emplace(arg);
}
else
m_args.emplace(arg);
}
}
CommandLineInterface& CommandLineInterface::Get() noexcept
{
return *s_instance;
}
CommandLineInterface::~CommandLineInterface()
{
s_instance = nullptr;
}
}

67
Runtime/Includes/Core/Engine.h git.filemode.normal_file
View File

@@ -0,0 +1,67 @@
#ifndef __SCOP_CORE_ENGINE__
#define __SCOP_CORE_ENGINE__
#include <cstdint>
#include <filesystem>
#include <Platform/Window.h>
#include <Platform/Inputs.h>
#include <Renderer/Renderer.h>
#include <Renderer/ScenesRenderer.h>
#include <Renderer/RenderCore.h>
#include <Core/Logs.h>
#include <Graphics/Scene.h>
#include <Core/CLI.h>
#ifdef DEBUG
#include <Debug/ImGuiRenderer.h>
#endif
namespace Scop
{
class ScopEngine
{
friend class Scene;
public:
ScopEngine(int ac, char** av, const std::string& title, std::uint32_t width, std::uint32_t height, std::filesystem::path assets_path);
void Run();
[[nodiscard]] inline const Window& GetWindow() const noexcept { return m_window; }
[[nodiscard]] inline std::filesystem::path GetAssetsPath() const { return m_assets_path; }
inline Scene& CreateMainScene(std::string_view name, SceneDescriptor desc) noexcept { p_main_scene = std::make_unique<Scene>(name, std::move(desc)); p_current_scene = p_main_scene.get(); return *p_main_scene; }
inline NonOwningPtr<Scene> GetRootScene() const noexcept { return p_main_scene.get(); }
constexpr void Quit() noexcept { m_running = false; }
[[nodiscard]] static inline bool IsInit() noexcept { return s_instance != nullptr; }
[[nodiscard]] static ScopEngine& Get() noexcept;
~ScopEngine();
private:
inline void SwitchToScene(NonOwningPtr<Scene> current) noexcept { p_current_scene = current; m_scene_changed = true; }
private:
static ScopEngine* s_instance;
Inputs m_inputs;
Renderer m_renderer;
#ifdef DEBUG
ImGuiRenderer m_imgui;
#endif
CommandLineInterface m_cli;
Window m_window;
SceneRenderer m_scene_renderer;
std::filesystem::path m_assets_path;
std::unique_ptr<RenderCore> p_renderer_core;
std::unique_ptr<Scene> p_main_scene;
NonOwningPtr<Scene> p_current_scene;
bool m_running = true;
bool m_scene_changed = false;
};
}
#endif

36
Runtime/Includes/Core/Enums.h git.filemode.normal_file
View File

@@ -0,0 +1,36 @@
#ifndef __SCOPE_CORE_ENUMS__
#define __SCOPE_CORE_ENUMS__
#include <cstddef>
namespace Scop
{
enum class LogType
{
Debug = 0,
Message,
Warning,
Error,
FatalError,
EndEnum
};
constexpr std::size_t LogTypeCount = static_cast<std::size_t>(LogType::EndEnum);
enum class Event
{
SceneHasChangedEventCode,
ResizeEventCode,
FrameBeginEventCode,
FatalErrorEventCode,
QuitEventCode,
MemoryChunkAllocationFailed,
EndEnum
};
constexpr std::size_t EventCount = static_cast<std::size_t>(Event::EndEnum);
}
#endif

14
Runtime/Includes/Core/EventBase.h git.filemode.normal_file
View File

@@ -0,0 +1,14 @@
#ifndef __SCOPE_CORE_BASE_EVENT__
#define __SCOPE_CORE_BASE_EVENT__
#include <Core/Enums.h>
namespace Scop
{
struct EventBase
{
virtual Event What() const = 0;
};
}
#endif

25
Runtime/Includes/Core/EventBus.h git.filemode.normal_file
View File

@@ -0,0 +1,25 @@
#ifndef __SCOPE_CORE_EVENT_BUS__
#define __SCOPE_CORE_EVENT_BUS__
#include <Core/EventBase.h>
#include <Core/EventListener.h>
#include <string>
#include <vector>
namespace Scop
{
class EventBus
{
public:
EventBus() = delete;
static void Send(const std::string& listener_name, const EventBase& event);
static void SendBroadcast(const EventBase& event);
inline static void RegisterListener(const EventListener& listener) { s_listeners.push_back(listener); }
~EventBus() = delete;
private:
inline static std::vector<EventListener> s_listeners;
};
}
#endif

27
Runtime/Includes/Core/EventListener.h git.filemode.normal_file
View File

@@ -0,0 +1,27 @@
#ifndef __SCOPE_CORE_EVENT_LISTENER__
#define __SCOPE_CORE_EVENT_LISTENER__
#include <Core/EventBase.h>
#include <functional>
#include <string>
namespace Scop
{
class EventListener
{
public:
EventListener() = delete;
EventListener(std::function<void(const EventBase&)> functor, std::string name);
[[nodiscard]] inline const std::string& GetName() const { return m_name; }
inline void Call(const EventBase& event) const noexcept { m_listen_functor(event); }
~EventListener() = default;
private:
std::function<void(const EventBase&)> m_listen_functor;
std::string m_name;
};
}
#endif

22
Runtime/Includes/Core/Format.h git.filemode.normal_file
View File

@@ -0,0 +1,22 @@
#ifndef __SCOPE_CORE_FORMAT__
#define __SCOPE_CORE_FORMAT__
#include <type_traits>
#include <string_view>
#include <tuple>
namespace Scop
{
template<typename T, typename = void>
struct IsOstreamable : std::false_type {};
template<typename T>
struct IsOstreamable<T, std::void_t<decltype(std::declval<std::ostream>() << std::declval<T>())>> : std::true_type {};
template<typename... Args, std::enable_if_t<std::conjunction_v<IsOstreamable<Args>...>, int> = 0>
auto Format(std::string_view format, const Args&... args);
}
#include <Core/Format.inl>
#endif

137
Runtime/Includes/Core/Format.inl git.filemode.normal_file
View File

@@ -0,0 +1,137 @@
#pragma once
#include <Core/Format.h>
#include <sstream>
#include <ostream>
// TODO : make single functions that manages stringstreams and ostreams
namespace Scop
{
namespace Internal
{
template<typename It>
void Format(std::stringstream& ss, It first, It last)
{
for(auto it = first; it != last; ++it)
{
switch(*it)
{
case '%':
throw std::invalid_argument{"too few arguments"};
case '/':
++it;
if(it == last)
throw std::invalid_argument{"stray '/'"};
[[fallthrough]];
default: ss << *it;
}
}
}
template<typename It, typename T, typename... Args>
void Format(std::stringstream& ss, It first, It last, const T& arg, const Args&... args)
{
for(auto it = first; it != last; ++it)
{
switch(*it)
{
case '%':
ss << arg;
return Format(ss, ++it, last, args...);
case '/':
++it;
if(it == last)
throw std::invalid_argument{"stray '/'"};
[[fallthrough]];
default: ss << *it;
}
}
throw std::invalid_argument{"too many arguments"};
}
template<typename It>
void Format(std::ostream& os, It first, It last)
{
for(auto it = first; it != last; ++it)
{
switch(*it)
{
case '%':
throw std::invalid_argument{"too few arguments"};
case '/':
++it;
if(it == last)
throw std::invalid_argument{"stray '/'"};
[[fallthrough]];
default: os << *it;
}
}
}
template<typename It, typename T, typename... Args>
void Format(std::ostream& os, It first, It last, const T& arg, const Args&... args)
{
for(auto it = first; it != last; ++it)
{
switch(*it)
{
case '%':
os << arg;
return Format(os, ++it, last, args...);
case '/':
++it;
if(it == last)
throw std::invalid_argument{"stray '/'"};
[[fallthrough]];
default: os << *it;
}
}
throw std::invalid_argument{"too many arguments"};
}
template<typename... Args>
struct Formatter
{
std::string_view format;
std::tuple<const Args&...> args;
};
template<typename... Args, std::size_t... Is>
void FormatHelper(std::stringstream& ss, const Formatter<Args...>& formatter, std::index_sequence<Is...>)
{
Format(ss, formatter.format.begin(), formatter.format.end(),
std::get<Is>(formatter.args)...);
}
template<typename... Args>
std::stringstream& operator<<(std::stringstream& ss, const Formatter<Args...>& printer)
{
FormatHelper(ss, printer, std::index_sequence_for<Args...>{});
return ss;
}
template<typename... Args, std::size_t... Is>
void FormatHelper(std::ostream& os, const Formatter<Args...>& formatter, std::index_sequence<Is...>)
{
Format(os, formatter.format.begin(), formatter.format.end(),
std::get<Is>(formatter.args)...);
}
template<typename... Args>
std::ostream& operator<<(std::ostream& os, const Formatter<Args...>& printer)
{
FormatHelper(os, printer, std::index_sequence_for<Args...>{});
return os;
}
}
template<typename... Args, std::enable_if_t<std::conjunction_v<IsOstreamable<Args>...>, int>>
auto Format(std::string_view format, const Args&... args)
{
return Internal::Formatter<Args...>{format, std::forward_as_tuple(args...)};
}
}

74
Runtime/Includes/Core/Logs.h git.filemode.normal_file
View File

@@ -0,0 +1,74 @@
#ifndef __SCOPE_CORE_LOGS__
#define __SCOPE_CORE_LOGS__
#include <string>
#include <string_view>
#include <Core/Enums.h>
namespace Scop
{
template<typename... Args>
void DebugLog(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args);
template<typename... Args>
void Error(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args);
template<typename... Args>
void Warning(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args);
template<typename... Args>
void Message(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args);
template<typename... Args>
void FatalError(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args);
template<typename... Args>
void Verify(bool cond, unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args);
class Logs
{
public:
Logs() = delete;
static void Report(LogType type, std::string message);
static void Report(LogType type, unsigned int line, std::string_view file, std::string_view function, std::string message);
~Logs() = delete;
};
#if defined(DEBUG)
template<typename... Args>
void Assert(bool cond, unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args);
#else
template<typename... Args>
void Assert(bool cond, unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args) {}
#endif
}
#include <Core/Logs.inl>
namespace Scop
{
#undef DebugLog
#define DebugLog(...) DebugLog(__LINE__, __FILE__, __func__, __VA_ARGS__)
#undef Message
#define Message(...) Message(__LINE__, __FILE__, __func__, __VA_ARGS__)
#undef Warning
#define Warning(...) Warning(__LINE__, __FILE__, __func__, __VA_ARGS__)
#undef Error
#define Error(...) Error(__LINE__, __FILE__, __func__, __VA_ARGS__)
#undef FatalError
#define FatalError(...) FatalError(__LINE__, __FILE__, __func__, __VA_ARGS__)
#undef Verify
#define Verify(cond, ...) Verify(cond, __LINE__, __FILE__, __func__, __VA_ARGS__)
#undef Assert
#define Assert(cond, ...) Assert(cond, __LINE__, __FILE__, __func__, __VA_ARGS__)
}
#endif

126
Runtime/Includes/Core/Logs.inl git.filemode.normal_file
View File

@@ -0,0 +1,126 @@
#pragma once
#include <Core/Logs.h>
#include <Core/Format.h>
#include <iostream>
namespace Scop
{
template<typename... Args>
void DebugLog(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args)
{
using namespace std::literals;
try
{
std::stringstream ss;
ss << Format(message, args...);
Logs::Report(LogType::Debug, line, file, function, ss.str());
}
catch(const std::exception& e)
{
Logs::Report(LogType::Error, "formatter exception catched in the log printer : "s + e.what());
}
}
template<typename... Args>
void Error(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args)
{
using namespace std::literals;
try
{
std::stringstream ss;
ss << Format(message, args...);
Logs::Report(LogType::Error, line, file, function, ss.str());
}
catch(const std::exception& e)
{
Logs::Report(LogType::Error, "formatter exception catched in the log printer : "s + e.what());
}
}
template<typename... Args>
void Warning(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args)
{
using namespace std::literals;
try
{
std::stringstream ss;
ss << Format(message, args...);
Logs::Report(LogType::Warning, line, file, function, ss.str());
}
catch(const std::exception& e)
{
Logs::Report(LogType::Error, "formatter exception catched in the log printer : "s + e.what());
}
}
template<typename... Args>
void Message(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args)
{
using namespace std::literals;
try
{
std::stringstream ss;
ss << Format(message, args...);
Logs::Report(LogType::Message, line, file, function, ss.str());
}
catch(const std::exception& e)
{
Logs::Report(LogType::Error, "formatter exception catched in the log printer : "s + e.what());
}
}
template<typename... Args>
void FatalError(unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args)
{
using namespace std::literals;
try
{
std::stringstream ss;
ss << Format(message, args...);
Logs::Report(LogType::FatalError, line, file, function, ss.str());
}
catch(const std::exception& e)
{
Logs::Report(LogType::Error, "formatter exception catched in the log printer : "s + e.what());
}
}
template<typename... Args>
void Verify(bool cond, unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args)
{
using namespace std::literals;
if(cond)
return;
try
{
std::stringstream ss;
ss << Format("Verification failed : %", message, args...);
Logs::Report(LogType::FatalError, line, file, function, ss.str());
}
catch(const std::exception& e)
{
Logs::Report(LogType::Error, "formatter exception catched in the log printer : "s + e.what());
}
}
#if defined(DEBUG)
template<typename... Args>
void Assert(bool cond, unsigned int line, std::string_view file, std::string_view function, std::string message, const Args&... args)
{
using namespace std::literals;
if(cond)
return;
try
{
std::stringstream ss;
ss << Format("Assertion failed : %", message, args...);
Logs::Report(LogType::FatalError, line, file, function, ss.str());
}
catch(const std::exception& e)
{
Logs::Report(LogType::Error, "formatter exception catched in the log printer : "s + e.what());
}
}
#endif
}

68
Runtime/Includes/Core/NativeScript.h git.filemode.normal_file
View File

@@ -0,0 +1,68 @@
#ifndef __SCOP_NATIVE_SCRIPT__
#define __SCOP_NATIVE_SCRIPT__
#include <functional>
#include <Core/Script.h>
namespace Scop
{
class NativeActorScript : public ActorScript
{
public:
NativeActorScript(std::function<void(NonOwningPtr<class Actor>)> on_init, std::function<void(NonOwningPtr<class Scene>, NonOwningPtr<class Actor>, class Inputs&, float)> on_update, std::function<void(NonOwningPtr<class Actor>)> on_quit)
: f_on_init(std::move(on_init)), f_on_update(std::move(on_update)), f_on_quit(std::move(on_quit))
{}
inline void OnInit(NonOwningPtr<class Actor> actor) override { if(f_on_init) f_on_init(actor); }
inline void OnUpdate(NonOwningPtr<class Scene> scene, NonOwningPtr<class Actor> actor, class Inputs& input, float delta) override { if(f_on_update) f_on_update(scene, actor, input, delta); }
inline void OnQuit(NonOwningPtr<class Actor> actor) override { if(f_on_quit) f_on_quit(actor); }
~NativeActorScript() = default;
private:
std::function<void(NonOwningPtr<class Actor>)> f_on_init;
std::function<void(NonOwningPtr<class Scene>, NonOwningPtr<class Actor>, class Inputs&, float)> f_on_update;
std::function<void(NonOwningPtr<class Actor>)> f_on_quit;
};
class NativeSpriteScript : public SpriteScript
{
public:
NativeSpriteScript(std::function<void(NonOwningPtr<class Sprite>)> on_init, std::function<void(NonOwningPtr<class Scene>, NonOwningPtr<class Sprite>, class Inputs&, float)> on_update, std::function<void(NonOwningPtr<class Sprite>)> on_quit)
: f_on_init(std::move(on_init)), f_on_update(std::move(on_update)), f_on_quit(std::move(on_quit))
{}
inline void OnInit(NonOwningPtr<class Sprite> sprite) override { if(f_on_init) f_on_init(sprite); }
inline void OnUpdate(NonOwningPtr<class Scene> scene, NonOwningPtr<class Sprite> sprite, class Inputs& input, float delta) override { if(f_on_update) f_on_update(scene, sprite, input, delta); }
inline void OnQuit(NonOwningPtr<class Sprite> sprite) override { if(f_on_quit) f_on_quit(sprite); }
~NativeSpriteScript() = default;
private:
std::function<void(NonOwningPtr<class Sprite>)> f_on_init;
std::function<void(NonOwningPtr<class Scene>, NonOwningPtr<class Sprite>, class Inputs&, float)> f_on_update;
std::function<void(NonOwningPtr<class Sprite>)> f_on_quit;
};
class NativeNarratorScript : public NarratorScript
{
public:
NativeNarratorScript(std::function<void()> on_init, std::function<void(NonOwningPtr<class Scene>, class Inputs&, float)> on_update, std::function<void()> on_quit)
: f_on_init(std::move(on_init)), f_on_update(std::move(on_update)), f_on_quit(std::move(on_quit))
{}
inline void OnInit() override { if(f_on_init) f_on_init(); }
inline void OnUpdate(NonOwningPtr<class Scene> scene, class Inputs& input, float delta) override { if(f_on_update) f_on_update(scene, input, delta); }
inline void OnQuit() override { if(f_on_quit) f_on_quit(); }
~NativeNarratorScript() = default;
private:
std::function<void()> f_on_init;
std::function<void(NonOwningPtr<class Scene>, class Inputs&, float)> f_on_update;
std::function<void()> f_on_quit;
};
}
#endif

45
Runtime/Includes/Core/Script.h git.filemode.normal_file
View File

@@ -0,0 +1,45 @@
#ifndef __SCOP_SCRIPT__
#define __SCOP_SCRIPT__
#include <Utils/NonOwningPtr.h>
namespace Scop
{
class ActorScript
{
public:
ActorScript() = default;
virtual void OnInit(NonOwningPtr<class Actor> actor) = 0;
virtual void OnUpdate(NonOwningPtr<class Scene> scene, NonOwningPtr<class Actor> actor, class Inputs& input, float delta) = 0;
virtual void OnQuit(NonOwningPtr<class Actor> actor) = 0;
virtual ~ActorScript() = default;
};
class SpriteScript
{
public:
SpriteScript() = default;
virtual void OnInit(NonOwningPtr<class Sprite> sprite) = 0;
virtual void OnUpdate(NonOwningPtr<class Scene> scene, NonOwningPtr<class Sprite> sprite, class Inputs& input, float delta) = 0;
virtual void OnQuit(NonOwningPtr<class Sprite> sprite) = 0;
virtual ~SpriteScript() = default;
};
class NarratorScript
{
public:
NarratorScript() = default;
virtual void OnInit() = 0;
virtual void OnUpdate(NonOwningPtr<class Scene> scene, class Inputs& input, float delta) = 0;
virtual void OnQuit() = 0;
virtual ~NarratorScript() = default;
};
}
#endif

19
Runtime/Includes/Core/UUID.h git.filemode.normal_file
View File

@@ -0,0 +1,19 @@
#ifndef __SCOP_CORE_UUID__
#define __SCOP_CORE_UUID__
#include <cstdint>
namespace Scop
{
class UUID
{
public:
UUID();
inline operator std::uint64_t() const noexcept { return m_uuid; }
private:
std::uint64_t m_uuid;
};
}
#endif