Implement Engine, World, and system initialization
Signed-off-by: Daniel Henry <iamdanhenry@gmail.com>
This commit is contained in:
45
.clang-format
Normal file
45
.clang-format
Normal file
@@ -0,0 +1,45 @@
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 2
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 0
|
||||
|
||||
|
||||
# Stop collapsing things to one line
|
||||
# AllowShortFunctionsOnASingleLine: Empty # or 'Empty' if you want only {} allowed
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
|
||||
# Top-level switches
|
||||
AlignTrailingComments: true # align // comments across consecutive lines
|
||||
BreakTemplateDeclarations: Yes
|
||||
|
||||
# Align declarations in neat columns
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignFunctionDeclarations: true # optional, aligns return types for funcs
|
||||
AlignFunctionPointers: true # optional
|
||||
|
||||
# Align assignments too (and pad short ops so columns line up)
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: true # include +=, -=, etc.
|
||||
PadOperators: true # only valid here
|
||||
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Merge
|
||||
IncludeCategories:
|
||||
- Regex: '^".*"'
|
||||
Priority: 1
|
||||
- Regex: '^<.*>'
|
||||
Priority: 2
|
||||
|
||||
|
||||
|
||||
47
CMakeLists.txt
Normal file
47
CMakeLists.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
project(CraftEngine
|
||||
VERSION 0.1.0
|
||||
LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
add_library(CraftEngine STATIC
|
||||
include/Craft/Engine.h
|
||||
src/Craft/Engine.cpp
|
||||
|
||||
include/Craft/World.h
|
||||
src/Craft/World.cpp
|
||||
|
||||
include/Craft/Graphics.h
|
||||
src/Craft/Graphics.cpp
|
||||
|
||||
include/Craft/Common.h
|
||||
)
|
||||
|
||||
target_include_directories(CraftEngine PUBLIC include)
|
||||
|
||||
# Fetch SDL3
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
SDL3
|
||||
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
|
||||
GIT_TAG release-3.2.22
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(SDL3)
|
||||
|
||||
target_link_libraries(CraftEngine PUBLIC SDL3::SDL3)
|
||||
|
||||
# FetchContent_Declare(
|
||||
# SDL3_image
|
||||
# GIT_REPOSITORY https://github.com/libsdl-org/SDL_image
|
||||
# GIT_TAG release-3.2.4
|
||||
# GIT_SHALLOW TRUE
|
||||
# )
|
||||
# FetchContent_MakeAvailable(SDL3_image)
|
||||
# target_link_libraries(CraftEngine PUBLIC SDL3_image:SDL3_image)
|
||||
|
||||
6
include/Craft.h
Normal file
6
include/Craft.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "Craft/Engine.h" // IWYU pragma: keep
|
||||
#include "Craft/World.h" // IWYU pragma: keep
|
||||
|
||||
// Convenience Macros
|
||||
#define GetEngine() craft::Engine::Get()
|
||||
#define GetWorld() craft::Engine::Get().GetWorld()
|
||||
22
include/Craft/Common.h
Normal file
22
include/Craft/Common.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio> // IWYU pragma: keep
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
namespace craft {
|
||||
|
||||
template <typename T>
|
||||
using unique = std::unique_ptr<T>;
|
||||
|
||||
template <typename T>
|
||||
using shared = std::shared_ptr<T>;
|
||||
|
||||
template <typename T>
|
||||
using weak = std::weak_ptr<T>;
|
||||
|
||||
template <typename keyType, typename valueType, typename Hasher = std::hash<keyType>>
|
||||
using Dict = std::unordered_map<keyType, valueType, Hasher>;
|
||||
|
||||
#define LOG(M, ...) std::printf(M "\n", ##__VA_ARGS__)
|
||||
|
||||
} // namespace craft
|
||||
113
include/Craft/Engine.h
Normal file
113
include/Craft/Engine.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include "Craft/Common.h"
|
||||
#include "Craft/Graphics.h"
|
||||
#include "Craft/World.h"
|
||||
#include "SDL3/SDL_timer.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace craft {
|
||||
|
||||
int main();
|
||||
|
||||
class Engine {
|
||||
public:
|
||||
////////// ENGINE
|
||||
friend int main();
|
||||
static Engine &Get() {
|
||||
static Engine instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
////////// WORLD
|
||||
template <typename T>
|
||||
void LoadWorld() {
|
||||
static_assert(std::is_base_of_v<World, T>, "LoadWorld<T>: T MUST inherit from craft::World!");
|
||||
mLoadedWorld = std::make_unique<T>();
|
||||
}
|
||||
|
||||
static void RegisterInitialWorld(std::function<unique<World>()> factory) {
|
||||
Get().initialWorldFactory = factory;
|
||||
}
|
||||
|
||||
World &GetWorld() {
|
||||
return *mLoadedWorld;
|
||||
}
|
||||
|
||||
private:
|
||||
Engine() : mRunning{true}, mTargetFixedFrameRate(60.f) {}
|
||||
|
||||
unique<Graphics> mGraphics = std::make_unique<Graphics>();
|
||||
|
||||
bool mRunning;
|
||||
|
||||
float mTargetFixedFrameRate;
|
||||
|
||||
void Run() {
|
||||
|
||||
static uint64_t lastTime = SDL_GetPerformanceCounter();
|
||||
static uint64_t frequency = SDL_GetPerformanceFrequency();
|
||||
static float accumulatedTime = 0.0f;
|
||||
|
||||
uint64_t currentTime = SDL_GetPerformanceCounter();
|
||||
float frameDeltaTime = (currentTime - lastTime) / (float)frequency;
|
||||
|
||||
lastTime = currentTime;
|
||||
|
||||
accumulatedTime += frameDeltaTime;
|
||||
|
||||
while (mRunning) {
|
||||
// Begin the world if needed
|
||||
if (!GetWorld().HasBegun()) {
|
||||
GetWorld().Begin();
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (!mGraphics->HandleEvents(event)) {
|
||||
mRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
float targetDeltaTime = 1.f / mTargetFixedFrameRate;
|
||||
while (accumulatedTime >= targetDeltaTime) {
|
||||
accumulatedTime -= targetDeltaTime;
|
||||
mLoadedWorld->FixedTick();
|
||||
}
|
||||
|
||||
mGraphics->Clear();
|
||||
|
||||
mLoadedWorld->Tick(frameDeltaTime);
|
||||
|
||||
mGraphics->Render();
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
//
|
||||
//
|
||||
// CRAZY WORLD INIT SHIT
|
||||
//
|
||||
//
|
||||
//////////
|
||||
std::function<unique<World>()> initialWorldFactory;
|
||||
|
||||
unique<World> mLoadedWorld;
|
||||
};
|
||||
|
||||
// TODO: Explain this shit, no shot I remember how this works in 3 days.
|
||||
|
||||
#define CRAFT_INITIALIZE(WorldClass) \
|
||||
namespace { \
|
||||
static int __craft_init_##WorldClass = []() { \
|
||||
static_assert(std::is_base_of_v<craft::World, WorldClass>, \
|
||||
"CRAFT_INITIALIZE: " #WorldClass " must inherit from craft::World!"); \
|
||||
craft::Engine::RegisterInitialWorld([]() -> std::unique_ptr<craft::World> { \
|
||||
return std::make_unique<WorldClass>(); \
|
||||
}); \
|
||||
return 0; \
|
||||
}(); \
|
||||
}
|
||||
|
||||
} // namespace craft
|
||||
23
include/Craft/Graphics.h
Normal file
23
include/Craft/Graphics.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace craft {
|
||||
|
||||
class Graphics {
|
||||
public:
|
||||
Graphics();
|
||||
~Graphics();
|
||||
void Clear();
|
||||
void Render();
|
||||
|
||||
inline SDL_Window *GetWindow() const { return mWindow; }
|
||||
inline SDL_Renderer *GetRenderer() const { return mRenderer; }
|
||||
|
||||
bool HandleEvents(SDL_Event &event);
|
||||
|
||||
private:
|
||||
SDL_Window *mWindow;
|
||||
SDL_Renderer *mRenderer;
|
||||
};
|
||||
|
||||
} // namespace craft
|
||||
16
include/Craft/World.h
Normal file
16
include/Craft/World.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace craft {
|
||||
class World {
|
||||
public:
|
||||
World();
|
||||
virtual void Begin();
|
||||
virtual void Tick(float deltaTime);
|
||||
virtual void FixedTick();
|
||||
|
||||
inline bool HasBegun() const { return mHasBegun; }
|
||||
|
||||
private:
|
||||
bool mHasBegun;
|
||||
};
|
||||
} // namespace craft
|
||||
19
src/Craft/Engine.cpp
Normal file
19
src/Craft/Engine.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "Craft/Engine.h"
|
||||
|
||||
int craft::main() {
|
||||
|
||||
Engine &engine = Engine::Get();
|
||||
|
||||
if (engine.initialWorldFactory) {
|
||||
engine.mLoadedWorld = engine.initialWorldFactory();
|
||||
} else {
|
||||
LOG("Error: No initial world registered! Use CRAFT_INITIALIZE(YourWorldClass)");
|
||||
return -1;
|
||||
}
|
||||
Engine::Get().Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
craft::main();
|
||||
}
|
||||
51
src/Craft/Graphics.cpp
Normal file
51
src/Craft/Graphics.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "Craft/Graphics.h"
|
||||
|
||||
namespace craft {
|
||||
Graphics::Graphics() : mWindow{nullptr}, mRenderer{nullptr} {
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
mWindow = SDL_CreateWindow("Craft Engine", 800, 600, 0);
|
||||
|
||||
// If in a debug build and on Apple, use OpenGL.
|
||||
// Otherwise just let SDL decide.
|
||||
#if defined(__APPLE__) && !defined(NDEBUG)
|
||||
static constexpr const char *kRendererName = "opengl";
|
||||
#else
|
||||
static constexpr const char *kRendererName = nullptr;
|
||||
#endif
|
||||
|
||||
mRenderer = SDL_CreateRenderer(mWindow, kRendererName);
|
||||
|
||||
// Not sure if this is needed on non-Apple machines, but
|
||||
// on my Mac it loads behind everything else.
|
||||
SDL_RaiseWindow(mWindow);
|
||||
}
|
||||
|
||||
Graphics::~Graphics() {
|
||||
if (mRenderer) {
|
||||
SDL_DestroyRenderer(mRenderer);
|
||||
}
|
||||
if (mWindow) {
|
||||
SDL_DestroyWindow(mWindow);
|
||||
}
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void Graphics::Clear() {
|
||||
SDL_SetRenderDrawColor(mRenderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(mRenderer);
|
||||
}
|
||||
|
||||
void Graphics::Render() {
|
||||
SDL_RenderPresent(mRenderer);
|
||||
}
|
||||
|
||||
bool Graphics::HandleEvents(SDL_Event &event) {
|
||||
|
||||
if (event.type == SDL_EVENT_QUIT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace craft
|
||||
13
src/Craft/World.cpp
Normal file
13
src/Craft/World.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "Craft/World.h"
|
||||
|
||||
namespace craft {
|
||||
|
||||
World::World() {}
|
||||
|
||||
void World::Begin() {
|
||||
mHasBegun = true;
|
||||
}
|
||||
void World::Tick(float deltaTime) {}
|
||||
void World::FixedTick() {}
|
||||
|
||||
} // namespace craft
|
||||
Reference in New Issue
Block a user