Compare commits

...

36 Commits

Author SHA1 Message Date
6a579a0512 chore(clang): update example files to follow clang formatting 2024-09-20 11:08:49 -06:00
b939530536 feat(platform): add platform header 2024-09-20 11:07:50 -06:00
baf933569b chore(cleanup): remove unused file 2024-09-20 11:07:20 -06:00
df8f0866c0 chore(clang): enforce clang format 2024-09-20 11:07:07 -06:00
d285346662 chore(git): add clang formatting files 2024-09-20 11:06:43 -06:00
63ed6f862f chore(git): add simple visual studio building script 2024-09-20 11:06:32 -06:00
e121126a37 chore(git): add Doxygen file
NOTE: Doxygen isn't yet used in the engine, however I do plan to use it
in the future
2024-09-20 11:06:13 -06:00
933bf16737 chore(git): add editorconfig 2024-09-20 11:05:36 -06:00
5e76c8a382 chore(example)(client): update to work with latest engine changes
- Change logging to explain the new fatal handler.
- Add custom termination handler example
2024-09-20 10:45:08 -06:00
91cf0d25d5 feat(platform): add platform specific popups
Please note! These changes have not yet been tested on POSIX platforms
(mac OR linux) so please do not expect them to work!
2024-09-20 10:44:12 -06:00
0eebacc28f feat(core): add termination handling extensability 2024-09-20 10:43:22 -06:00
51de852ab1 feat(logger): create more modular logger 2024-09-20 04:53:33 -06:00
1015569263 feat(core): create an application that the engine manages instead of the user 2024-09-16 23:28:37 -06:00
8489b1e3a2 feat(examples)(client): updates to work with new logging ownership 2024-09-16 23:28:09 -06:00
b17c160d5c feat(logger): handles ownership of streams 2024-09-16 23:27:50 -06:00
567c1ae1c0 chore(cmake): only use warnings as errors on release builds 2024-09-16 23:26:38 -06:00
07a7d7fb52 chore(git): correct build folder wildcard 2024-09-16 23:26:11 -06:00
24f4fb3841 chore(example): fix unicode issue (thanks chatgpt) 2024-09-15 04:37:03 -06:00
ea1f25d26b example(client)(logging): showcase logging 2024-09-15 04:33:23 -06:00
6a11db9a2e feat(logging): add extra logging streams 2024-09-15 04:32:46 -06:00
bf2847cc09 feat(logging): implement logger and logging macros 2024-09-15 04:14:31 -06:00
9db13726b5 feat(build): update precompiled header 2024-09-15 04:14:01 -06:00
2f5b662a37 chore(git): remove clang format file 2024-09-15 04:13:35 -06:00
8afaa3cce3 feat(cmake): add precompiled headers 2024-09-15 03:34:48 -06:00
998300975d chore: something 2024-09-15 02:49:49 -06:00
96f84b2c04 chore: idk 2024-09-15 02:47:24 -06:00
c7f052208c chore(cmake): revert changes 2024-09-15 02:46:18 -06:00
bcfd916c04 fix(cmake): update version correctly 2024-09-15 02:40:10 -06:00
1a7f3415ad chore(cmake) propagate version 2024-09-15 02:37:09 -06:00
42c0af0dbf chore(examples): update to use new header 2024-09-15 02:31:13 -06:00
fe2270c539 chore(cmake): fix bad cmake 2024-09-15 02:26:40 -06:00
66866387f1 chore(modules): remove complex modules and switch to normal headers/sources 2024-09-15 02:18:15 -06:00
df2036bd0e chore(README): show how to use engine in a cmake project 2024-09-15 01:48:14 -06:00
557d106428 chore(docs): update build instructions 2024-09-15 01:44:52 -06:00
4a47835d6f refactor(engine): move files to new structure\ 2024-09-15 01:37:29 -06:00
2c0448083d refactor(engine): remove outdated files as part of project restructure 2024-09-15 01:37:02 -06:00
55 changed files with 822 additions and 7521 deletions

18
.bumpversion.cfg Normal file
View File

@ -0,0 +1,18 @@
[bumpversion]
current_version = ALPHA-2.0.0
commit = True
tag = True
tag_name = v{new_version}
[bumpversion:file:VERSION]
search = {current_version}
replace = {new_version}
[bumpversion:part:major]
first_value = 2
[bumpversion:part:minor]
first_value = 0
[bumpversion:part:patch]
first_value = 0

37
.clang-format Normal file
View File

@ -0,0 +1,37 @@
---
BasedOnStyle: "Chromium"
Standard: Cpp20
# I like K&R, fight me
IndentWidth: 4
TabWidth: 4
UseTab: Never
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Attach
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
AllowShortEnumsOnASingleLine: false
AlignConsecutiveAssignments: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AlignAfterOpenBracket: false
AllowShortFunctionsOnASingleLine: None
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PointerAlignment: Left
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4

32
.clang-tidy Normal file
View File

@ -0,0 +1,32 @@
---
Checks: >
-*,
readability-*,
modernize-*,
cppcoreguidelines-*,
performance-*,
bugprone-*,
clang-analyzer-*,
misc-*,
google-*,
cert-*,
portability-*,
cppcoreguidelines-pro-bounds-array-to-pointer-decay
WarningsAsErrors: ''
HeaderFilterRegex: '.*'
FormatStyle: none
User: ''
CheckOptions:
- key: readability-identifier-naming.VariableCase
value: lower_case
- key: readability-identifier-naming.FunctionCase
value: CamelCase
- key: modernize-use-auto
value: 0
- key: modernize-use-nullptr
value: 1
- key: cppcoreguidelines-non-private-member-variables-in-classes
value: 1
- key: modernize-use-override
value: 1

22
.editorconfig Normal file
View File

@ -0,0 +1,22 @@
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
[*.cpp]
indent_style = space
indent_size = 4
[*.hpp]
indent_style = space
indent_size = 4
charset = utf-8
[Makefile]
indent_style = tab
[*.bin]
binary = true

22
.gitignore vendored
View File

@ -1,22 +1,6 @@
# IDE Files
.vscode/
.jb/
# IDE Generated Files
cmake-build-debug/
.idea/
# Build directories
build/
build-vs/
build-debug/
build-release/
build-minsizerel/
cmake-build-debug/
# Build folders
build*/
# Tooling files
output.txt
buildall.bat
typer.py
# Sandbox Assets
assets/
art/

View File

@ -1,242 +1,91 @@
cmake_minimum_required(VERSION 3.28)
CMAKE_MINIMUM_REQUIRED(VERSION 3.18)
PROJECT(ICEngine LANGUAGES CXX C VERSION 1.0.0)
project(IsoEngine LANGUAGES CXX)
# Read version for logger
FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION_TEXT)
STRING(STRIP "${VERSION_TEXT}" VERSION_TEXT)
STRING(REGEX MATCH "([A-Z]+)-([0-9]+)\\.([0-9]+)\\.([0-9]+)" _ ${VERSION_TEXT})
SET(PROJECT_VERSION ${CMAKE_MATCH_1}-${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${CMAKE_MATCH_4})
# Options for shared/static libraries, and client/server examples
option(BUILD_SHARED_LIBS "Build engine library dependencies as shared (DLLs)" OFF)
option(BUILD_CLIENT "Build the client example" ON)
option(BUILD_SERVER "Build the server example" ON)
OPTION(BUILD_ENGINE_AS_SHARED_LIBRARY "Build engine as a shared library" OFF)
OPTION(BUILD_DEPS_AS_SHARED_LIBRARIES "Builds engine's dependencies as shared libraries" OFF)
OPTION(BUILD_EXAMPLES "Builds examples to showcase engine" ON)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "No build type specified, defaulting to Debug")
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE)
endif()
IF (CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release;MinSizeRel" CACHE STRING "" FORCE)
ELSE ()
IF (NOT CMAKE_BUILD_TYPE)
MESSAGE(" | ICEngine | No build type specified, defaulting to Debug")
SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build: Debug, Release, MinSizeRel" FORCE)
ENDIF ()
ENDIF ()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_XCODE_GENERATE_SCHEME ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
SET(ARCHITECTURE "x64")
SET(CMAKE_CXX_STANDARD 20)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_XCODE_GENERATE_SCHEME ON)
SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Output directory settings
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
MESSAGE(STATUS "Building for x64 architecture")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64")
if(POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${ARCH_DIR}/bin)
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${ARCH_DIR}/lib)
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${ARCH_DIR}/lib)
set(FETCHCONTENT_QUIET OFF)
include(FetchContent)
IF (MSVC)
IF (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
ADD_COMPILE_OPTIONS(/W4 /WX)
ENDIF ()
ELSE ()
IF (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
ADD_COMPILE_OPTIONS(-Wall -Wextra -Werror -Wpedantic)
ENDIF ()
ENDIF ()
# enet is header-only
set(ENET_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/vendor/enet")
INCLUDE_DIRECTORIES(engine/)
FetchContent_Declare(
raylib
URL https://github.com/raysan5/raylib/archive/refs/tags/5.0.zip
SET(EngineSources
engine/src/core/ICEApplication.cpp
)
set(BUILD_EXAMPLES OF CACHE BOOL "" FORCE)
set(SUPPORT_EVENTS_WAITING ON CACHE BOOL "" FORCE)
set(SUPPORT_BUSY_WAIT_LOOP OFF CACHE BOOL "" FORCE)
IF (WIN32)
LIST(APPEND EngineSources
engine/src/platform/windows/WindowsPopup.cpp
)
ELSEIF (UNIX)
LIST(APPEND EngineSources
engine/src/platform/posix/PosixPopup.cpp
)
ENDIF()
if (BUILD_SHARED_LIBS)
set(RAYLIB_LIBTYPE SHARED)
endif()
FetchContent_MakeAvailable(raylib)
SET(PrecompiledHeader "pch.h")
FetchContent_Declare(
imgui
GIT_REPOSITORY https://github.com/ocornut/imgui.git
GIT_TAG v1.91.1
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(imgui)
IF (BUILD_ENGINE_AS_SHARED_LIBRARY)
ADD_LIBRARY(ICEngine SHARED ${EngineSources})
SET_TARGET_PROPERTIES(ICEngine PROPERTIES
OUTPUT_NAME "ICEngine"
WINDOWS_EXPORT_ALL_SYMBOLS ON
)
ELSE ()
ADD_LIBRARY(ICEngine STATIC ${EngineSources})
SET_TARGET_PROPERTIES(ICEngine PROPERTIES OUTPUT_NAME "ICEngine")
ENDIF ()
add_library(ImGui ${imgui_SOURCE_DIR}/imgui.cpp
${imgui_SOURCE_DIR}/imgui_demo.cpp
${imgui_SOURCE_DIR}/imgui_draw.cpp
${imgui_SOURCE_DIR}/imgui_tables.cpp
${imgui_SOURCE_DIR}/imgui_widgets.cpp
)
target_include_directories(ImGui PUBLIC ${imgui_SOURCE_DIR})
TARGET_COMPILE_DEFINITIONS(ICEngine PUBLIC PROJECT_VERSION="${PROJECT_VERSION}")
TARGET_INCLUDE_DIRECTORIES(ICEngine PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
FetchContent_Declare(
rlimgui
GIT_REPOSITORY https://github.com/raylib-extras/rlImGui.git
GIT_TAG main
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(rlimgui)
IF (BUILD_EXAMPLES)
INCLUDE_DIRECTORIES(examples/server)
INCLUDE_DIRECTORIES(examples/client)
FetchContent_Declare(
box2d
GIT_REPOSITORY https://github.com/erincatto/box2d.git
GIT_TAG v3.0.0
)
FetchContent_MakeAvailable(box2d)
ADD_EXECUTABLE(server_example examples/server/server.cpp)
TARGET_LINK_LIBRARIES(server_example PRIVATE ICEngine)
FetchContent_Declare(
entt
GIT_REPOSITORY https://github.com/skypjack/entt.git
GIT_TAG v3.13.2
)
FetchContent_MakeAvailable(entt)
ADD_EXECUTABLE(client_example examples/client/client.cpp)
TARGET_LINK_LIBRARIES(client_example PRIVATE ICEngine)
FetchContent_Declare(
physfs
GIT_REPOSITORY https://github.com/icculus/physfs.git
GIT_TAG release-3.2.0
)
# PhysFS settings (default: static)
set(PHYSFS_BUILD_STATIC ON CACHE BOOL "Build PhysFS static library" FORCE)
set(PHYSFS_BUILD_SHARED OFF CACHE BOOL "Do not build PhysFS shared library" FORCE)
if(BUILD_SHARED_LIBS)
set(PHYSFS_BUILD_SHARED ON CACHE BOOL "Build PhysFS shared library" FORCE)
set(PHYSFS_BUILD_STATIC OFF CACHE BOOL "Do not build PhysFS static library" FORCE)
endif()
set(PHYSFS_BUILD_TEST OFF CACHE BOOL "Disable PhysFS test program" FORCE)
FetchContent_MakeAvailable(physfs)
# Main Engine Library
set(ENGINE_SOURCES
src/IsoEngine.cpp
src/enet_client.cpp
src/enet_server.cpp
src/Logger.cpp
src/components/sprite_component.cpp
src/components/physics_component.cpp
src/components/input_component.cpp
src/components/ui_component.cpp
src/scene_manager.cpp
src/filepacker.cpp
)
if (WIN32)
list(APPEND ENGINE_SOURCES src/platform/windows/FatalHandlerWindows.cpp)
elseif(UNIX)
list(APPEND ENGINE_SOURCES src/platform/posix/FatalHandlerPosix.cpp)
endif()
add_library(IsoEngine ${ENGINE_SOURCES})
target_include_directories(IsoEngine PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/src/components
${raylib_SOURCE_DIR}
${imgui_SOURCE_DIR}
${rlimgui_SOURCE_DIR}
${box2d_SOURCE_DIR}/include
${physfs_SOURCE_DIR}/src
${entt_SOURCE_DIR}/src
${ENET_INCLUDE_DIR}
)
target_link_libraries(IsoEngine PRIVATE raylib box2d EnTT::EnTT)
target_precompile_headers(IsoEngine PRIVATE src/IsoEnginePCH.h)
# PhysFS linkage
if(BUILD_SHARED_LIBS)
target_link_libraries(IsoEngine PRIVATE PhysFS::PhysFS)
else()
target_link_libraries(IsoEngine PRIVATE PhysFS::PhysFS-static)
target_compile_definitions(IsoEngine PRIVATE PHYSFS_STATIC)
endif()
# rlImGui library linking
add_library(rlImGui ${rlimgui_SOURCE_DIR}/rlImGui.cpp)
target_include_directories(rlImGui PUBLIC ${rlimgui_SOURCE_DIR} ${imgui_SOURCE_DIR})
target_link_libraries(rlImGui PRIVATE raylib ImGui)
target_link_libraries(IsoEngine PRIVATE ImGui rlImGui)
# Example executables (client/server)
if(BUILD_CLIENT)
# Client executable
set(CLIENT_SOURCE "${CMAKE_CURRENT_LIST_DIR}/sandbox/client.cpp")
add_executable(client ${CLIENT_SOURCE})
target_include_directories(client PRIVATE ${ENET_INCLUDE_DIR})
target_link_libraries(client PRIVATE IsoEngine raylib)
# Platform-specific linking for client (Windows)
if(WIN32)
target_link_libraries(client PRIVATE winmm ws2_32)
endif()
# Server executable
set(SERVER_SOURCE "${CMAKE_CURRENT_LIST_DIR}/sandbox/server.cpp")
add_executable(server ${SERVER_SOURCE})
target_include_directories(server PRIVATE ${ENET_INCLUDE_DIR})
target_link_libraries(server PRIVATE IsoEngine)
# Platform-specific linking for server (Windows)
if(WIN32)
target_link_libraries(server PRIVATE winmm ws2_32)
endif()
endif()
# Platform-specific linking for IsoEngine (Raylib and Winsock for ENet on Windows)
if(WIN32)
target_link_libraries(IsoEngine PRIVATE winmm ws2_32)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS)
add_definitions(-D_HAS_EXCEPTIONS=0)
elseif(APPLE)
target_link_libraries(IsoEngine PRIVATE "-framework CoreVideo" "-framework IOKit" "-framework Cocoa" "-framework GLUT" "-framework OpenGL")
else()
target_link_libraries(IsoEngine PRIVATE m pthread GL dl X11)
endif()
# Build Configuration Optimizations
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Configuring Debug build: No optimizations applied.")
target_compile_definitions(IsoEngine PRIVATE ENABLE_LOGGING)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
message(STATUS "Configuring Release build: Applying moderate optimizations.")
target_compile_options(IsoEngine PRIVATE -O2)
if(BUILD_CLIENT OR BUILD_SANDBOX)
target_compile_options(client PRIVATE -O2)
target_compile_options(server PRIVATE -O2)
endif()
# Strip symbols after building
if(NOT MSVC)
add_custom_command(TARGET IsoEngine POST_BUILD
COMMAND ${CMAKE_STRIP} --strip-unneeded $<TARGET_FILE:IsoEngine>
COMMENT "Stripping unneeded symbols from the IsoEngine binary in Release build."
)
if(BUILD_CLIENT OR BUILD_SANDBOX)
add_custom_command(TARGET client POST_BUILD
COMMAND ${CMAKE_STRIP} --strip-unneeded $<TARGET_FILE:client>
COMMENT "Stripping unneeded symbols from the client binary in Release build."
)
add_custom_command(TARGET server POST_BUILD
COMMAND ${CMAKE_STRIP} --strip-unneeded $<TARGET_FILE:server>
COMMENT "Stripping unneeded symbols from the server binary in Release build."
)
endif()
endif()
elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
message(STATUS "Configuring MinSizeRel build: Applying aggressive size optimizations.")
target_compile_options(IsoEngine PRIVATE -Os -ffunction-sections -fdata-sections)
target_link_options(IsoEngine PRIVATE -Wl,--gc-sections -Wl,--as-needed)
# Strip symbols aggressively after building
if(NOT MSVC)
add_custom_command(TARGET IsoEngine POST_BUILD
COMMAND ${CMAKE_STRIP} --strip-all $<TARGET_FILE:IsoEngine>
COMMENT "Stripping all symbols from the IsoEngine binary in MinSizeRel build."
)
if(BUILD_CLIENT OR BUILD_SANDBOX)
add_custom_command(TARGET client POST_BUILD
COMMAND ${CMAKE_STRIP} --strip-all $<TARGET_FILE:client>
COMMENT "Stripping all symbols from the client binary in MinSizeRel build."
)
add_custom_command(TARGET server POST_BUILD
COMMAND ${CMAKE_STRIP} --strip-all $<TARGET_FILE:server>
COMMENT "Stripping all symbols from the server binary in MinSizeRel build."
)
endif()
endif()
endif()
SET_TARGET_PROPERTIES(server_example PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
SET_TARGET_PROPERTIES(client_example PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
ENDIF ()

35
Doxygen Normal file
View File

@ -0,0 +1,35 @@
PROJECT_NAME = "ICEngine"
PROJECT_NUMBER = "ALPHA-2.0.0"
OUTPUT_DIRECTORY = docs-gen
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = YES
INPUT = src/ include/
FILE_PATTERNS = *.cpp *.h *.hpp
RECURSIVE = YES
# Default to html
GENERATE_HTML = YES
GENERATE_LATEX = NO
GENERATE_MAN = NO
INLINE_INHERITED_MEMB = YES
FULL_PATH_NAMES = YES
EXTRACT_NAMESPACE = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_ANON_NSPACES = NO
SHOW_INCLUDE_FILES = YES
OPTIMIZE_OUTPUT_FOR_C = YES
GENERATE_AUTOGEN_DEF = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
SORT_MEMBER_DOCS = YES
SORT_GROUP_NAMES = YES
ENUM_VALUES_PER_LINE = 1

View File

@ -1,8 +1,30 @@
# Iso Engine
# ICEngine
Smol little game engine since I have no idea what I'm doing
# Notice:
## Building
Find more info about building the project in the `docs/Building.md` file.
Since this uses the newer cpp modules, you need to make sure your compiler + build system + IDE supports this. You can
find more info [on this stack overflow post](https://stackoverflow.com/questions/57300495/how-to-use-c20-modules-with-cmake).
(CMake >= 3.28)
# Using the engine as a library
You're more than welcome to use this engine for your game. The recommended way to build the project is using CMake:
### Fetch Content:
```cmake
# Enable FetchContent module
include(FetchContent)
# Fetch the external repository
FetchContent_Declare(
ICEngine
GIT_REPOSITORY http://proudcricle/illyum/ICEngine.git
GIT_TAG main
)
# Then add your sources and executable
add_executable(MyGame main.cpp)
# Link the ICEngine library to your project
target_link_libraries(MyGame PRIVATE ICEngine)
```

1
VERSION Normal file
View File

@ -0,0 +1 @@
ALPHA-2.0.0

19
docs/Building.md Normal file
View File

@ -0,0 +1,19 @@
# Building
ICEngine supports both single and multi type configuration types:
Make/Ninja
```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
```
\- OR -
Visual Studio:
```bash
cmake -S . -B build -G "Visual Studio 16 2019" # or your preferred Visual Studio version
cmake --build build --config Debug
cmake --build build --config Release
```

39
docs/Developers.md Normal file
View File

@ -0,0 +1,39 @@
# Dev Notes
### Version Bumping
We use a tool called `bump2version` to manage bumping versions in the project. To ensure a clean git history and avoid
conflicts, follow these steps when bumping the version:
1. **Before bumping the version**, always `git pull` to ensure you have the latest changes from the repository.
2. Ensure no other copies of the repo are being worked on or committed before running the `bump2version` tool.
3. Bump the version using the command:
```bash
bumpversion [major|minor|patch]
```
This will:
1. Update the version in the VERSION file.
1. Automatically commit the version bump.
1. Create a Git tag with the new version (e.g., vALPHA-2.0.1).
Push your changes and the tag to the remote repository after bumping the version:
```bash
git push origin master --tags
```
ersioning Guidelines
We follow a versioning structure of ALPHA-major.minor.patch. Heres a breakdown of the versioning rules:
- **Major**: The major version is incremented for significant changes that introduce new features or incompatible API
changes.
- **Minor**: The minor version is incremented for adding new functionality in a backwards-compatible manner.
- **Patch**: The patch version is incremented for bug fixes and minor improvements that dont affect the existing
functionality.
This will be managed by a CI/CD pipeline (or Gitea Actions) later down the line, but for now, follow these manual steps
carefully to ensure version consistency.

View File

@ -1,20 +0,0 @@
# Ideas for this/future engine
Also just an outline for stuff
- Custom Logger
- CMake / Premake / XMake
- Event System
- Window Handler (support multiple windows)
- Layer system
- Math helpers
- Static/Dynamic linking
- Export or Build (export game as game file, or build your own exe directly)
- Shader System
- Entity Component System?
- Profiling
- Scripting? (lua?) + while-running / preprocessed scripts
- Tools (Sprite Sheet Tools, etc)
- Asset Manager / Pipeline (choose between .pak or individual files)
- Physics
- Collision Detection

12
engine/ICEngine.hpp Normal file
View File

@ -0,0 +1,12 @@
//
// Created by illyum on 9/15/2024.
//
#ifndef ICENGINE_HPP
#define ICENGINE_HPP
#include "src/core/Logger.hpp"
#include "src/core/ICEApplication.hpp"
#include "src/platform/Platform.hpp"
#endif //ICENGINE_HPP

17
engine/pch.hpp Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <ctime>
#include <format>
#include <memory>
#include <string>
#include <vector>
#include <chrono>
#include <csignal>
#include <cstdarg>
#include <iomanip>
#include <utility>
#include <fstream>
#include <sstream>
#include <iostream>
#include <exception>
#include <functional>

View File

@ -0,0 +1,47 @@
//
// Created by illyum on 9/15/2024.
//
#include "ICEngine.hpp"
#include "pch.hpp"
namespace ICEngine {
ICEApplication::TerminationHandler ICEApplication::customHandler = ICEApplication::DefaultTerminationHandler;
void ICEApplication::SetTerminationHandler(TerminationHandler handler) {
if (handler) {
customHandler = handler;
} else {
customHandler = DefaultTerminationHandler;
}
}
void ICEApplication::HandleFatalError(const std::string &message) {
if (customHandler) {
customHandler(message);
} else {
DefaultTerminationHandler(message);
}
}
void ICEApplication::DefaultTerminationHandler(const std::string &message) {
Log::GetCoreLogger()->Log(CRITICAL, __FILE__, __LINE__, __FUNCTION__, message);
std::exit(EXIT_FAILURE);
}
void StartApplication() {
Log::Init();
CORE_LOG_TRACE("Starting ICEngine");
ICEApplication *app = CreateICEApplication();
if (app) {
CORE_LOG_TRACE("Starting User Application");
app->Run();
delete app;
} else {
CORE_LOG_FATAL("Could not start User Application");
}
CORE_LOG_TRACE("Shutting down ICEngine");
}
}

View File

@ -0,0 +1,37 @@
//
// Created by illyum on 9/15/2024.
//
#pragma once
#include <pch.hpp>
#include "Logger.hpp"
namespace ICEngine {
class ICEApplication {
public:
ICEApplication() {
}
virtual ~ICEApplication() {
}
virtual void Run() = 0;
using TerminationHandler = std::function<void(const std::string &)>;
static void SetTerminationHandler(TerminationHandler handler);
static void HandleFatalError(const std::string &message);
private:
static TerminationHandler customHandler;
static void DefaultTerminationHandler(const std::string &message);
};
void StartApplication();
// Application-specific function that will be defined by the user
extern ICEApplication *CreateICEApplication();
}

214
engine/src/core/Logger.hpp Normal file
View File

@ -0,0 +1,214 @@
//
// Created by illyum on 9/14/2024.
//
#pragma once
#include <pch.hpp>
namespace ICEngine {
enum LogLevel {
OFF = 0,
TRACE,
DEBUG,
WARN,
ERROR,
CRITICAL,
FATAL
};
class LogSink {
public:
virtual ~LogSink() = default;
virtual void Log(const std::string &message) = 0;
};
class ConsoleSink : public LogSink {
public:
void Log(const std::string &message) override {
std::cout << message << std::endl;
}
};
class FileSink : public LogSink {
public:
explicit FileSink(const std::string &filename) {
fileStream.open(filename);
}
void Log(const std::string &message) override {
if (fileStream.is_open()) {
fileStream << message << std::endl;
}
}
private:
std::ofstream fileStream;
};
class Logger {
public:
explicit Logger(const char *name) : name(name) {
}
void SetLevel(LogLevel level) {
this->level = level;
}
void AddSink(std::shared_ptr<LogSink> sink) {
sinks.push_back(std::move(sink));
}
template<typename... Args>
void Log(LogLevel level, const char *file, int line, const char *func, const std::string &formatStr,
Args &&... args) {
if (level < this->level) return;
std::string logMessage = formatMessage(level, file, line, func,
format(formatStr, std::forward<Args>(args)...));
for (const auto &sink: sinks) {
sink->Log(logMessage);
}
}
private:
const char *name;
std::vector<std::shared_ptr<LogSink> > sinks;
LogLevel level = DEBUG;
static const char *levelToString(LogLevel level) {
switch (level) {
case TRACE: return "TRACE";
case DEBUG: return "DEBUG";
case WARN: return "WARN";
case ERROR: return "ERROR";
case CRITICAL: return "CRITICAL";
case FATAL: return "FATAL";
default: return "UNKNOWN";
}
}
static std::string getCurrentTime() {
auto now = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::ostringstream oss;
oss << std::put_time(std::localtime(&time), "%Y/%m/%d %H:%M:%S");
return oss.str();
}
static std::string truncateFilePath(const char *file) {
std::string path(file);
size_t pos = path.find_last_of("/\\");
if (pos != std::string::npos && pos > 3) {
return "..." + path.substr(pos - 3);
}
return path;
}
template<typename... Args>
std::string format(const std::string &formatStr, Args &&... args) {
std::ostringstream oss;
formatHelper(oss, formatStr, std::forward<Args>(args)...);
return oss.str();
}
void formatHelper(std::ostringstream &oss, const std::string &formatStr) {
oss << formatStr;
}
template<typename T, typename... Args>
void formatHelper(std::ostringstream &oss, const std::string &formatStr, T &&firstArg,
Args &&... remainingArgs) {
size_t pos = formatStr.find("{}");
if (pos != std::string::npos) {
oss << formatStr.substr(0, pos) << std::forward<T>(firstArg);
formatHelper(oss, formatStr.substr(pos + 2), std::forward<Args>(remainingArgs)...);
} else {
oss << formatStr;
}
}
std::string formatMessage(LogLevel level, const char *file, int line, const char *func,
const std::string &message) {
std::ostringstream oss;
oss << getCurrentTime() << " ";
oss << truncateFilePath(file) << ":" << line << ":" << func << " ";
oss << "[" << name << "] ";
oss << "[" << levelToString(level) << "]: ";
oss << message;
return oss.str();
}
};
class Log {
public:
static void Init() {
static bool isInitialized = false;
if (isInitialized) {
GetCoreLogger()->Log(WARN, __FILE__, __LINE__, __FUNCTION__,
"Logger already initialized. Skipping re-initialization.");
return;
}
GetCoreLogger();
GetAppLogger();
isInitialized = true;
}
static std::shared_ptr<Logger> &GetCoreLogger() {
static std::shared_ptr<Logger> CoreLogger(new Logger("CORE"));
return CoreLogger;
}
static std::shared_ptr<Logger> &GetAppLogger() {
static std::shared_ptr<Logger> AppLogger(new Logger("APP"));
return AppLogger;
}
private:
Log() = delete;
Log(const Log &) = delete;
Log &operator=(const Log &) = delete;
};
#define CORE_LOG_FATAL(message) \
do { \
ICEngine::Log::GetCoreLogger()->Log(ICEngine::FATAL, __FILE__, __LINE__, __FUNCTION__, message); \
ICEngine::ICEApplication::HandleFatalError(message); \
} while (0)
#define LOG_FATAL(message) \
do { \
ICEngine::Log::GetAppLogger()->Log(ICEngine::FATAL, __FILE__, __LINE__, __FUNCTION__, message); \
ICEngine::ICEApplication::HandleFatalError(message); \
} while (0)
#ifndef NDEBUG
#define CORE_LOG_TRACE(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::TRACE, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define CORE_LOG_DEBUG(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::DEBUG, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define CORE_LOG_WARN(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::WARN, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define CORE_LOG_ERROR(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::ERROR, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define CORE_LOG_CRITICAL(message, ...) ICEngine::Log::GetCoreLogger()->Log(ICEngine::CRITICAL, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define LOG_TRACE(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::TRACE, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define LOG_DEBUG(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::DEBUG, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define LOG_WARN(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::WARN, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define LOG_ERROR(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::ERROR, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#define LOG_CRITICAL(message, ...) ICEngine::Log::GetAppLogger()->Log(ICEngine::CRITICAL, __FILE__, __LINE__, __FUNCTION__, message, ##__VA_ARGS__)
#else
#define CORE_LOG_TRACE(message, ...)
#define CORE_LOG_DEBUG(message, ...)
#define CORE_LOG_WARN(message, ...)
#define CORE_LOG_ERROR(message, ...)
#define CORE_LOG_CRITICAL(message, ...)
#define LOG_TRACE(message, ...)
#define LOG_DEBUG(message, ...)
#define LOG_WARN(message, ...)
#define LOG_ERROR(message, ...)
#define LOG_CRITICAL(message, ...)
#endif
}

View File

@ -0,0 +1,17 @@
//
// Created by illyum on 9/20/2024.
//
#pragma once
#include <pch.hpp>
namespace Platform {
void ShowPopup(const char *message);
void ShowPopup(const char *title, const char *message);
void ShowPopup(const std::string &message);
void ShowPopup(const std::string &title, const std::string &message);
}

View File

@ -0,0 +1,17 @@
//
// Created by illyum on 9/20/2024.
//
#include "../Platform.hpp"
#include <pch.hpp>
namespace Platform {
void ShowPopup(const char* message) {
std::string command = "zenity --info --text=\"";
command += message;
command += "\"";
system(command.c_str());
}
}

View File

@ -0,0 +1,25 @@
//
// Created by illyum on 9/20/2024.
//
#include <pch.hpp>
#include "../Platform.hpp"
#include <windows.h>
namespace Platform {
void ShowPopup(const char *message) {
MessageBoxA(nullptr, message, "ICEngine", MB_OK);
}
void ShowPopup(const char *title, const char *message) {
MessageBoxA(nullptr, message, title, MB_OK);
}
void ShowPopup(const std::string &message) {
MessageBoxA(nullptr, message.c_str(), "ICEngine", MB_OK);
}
void ShowPopup(const std::string &title, const std::string &message) {
MessageBoxA(nullptr, message.c_str(), title.c_str(), MB_OK);
}
}

119
examples/client/client.cpp Normal file
View File

@ -0,0 +1,119 @@
//
// Created by illyum on 9/15/2024.
//
#include <ICEngine.hpp>
#include <fstream>
#include <src/platform/Platform.hpp>
void ShowLogger();
void CustomTermHandler(const std::string &message);
int main() {
// You can set a custom termination handler/function.
// Make sure you do this before you start the application!!!
ICEngine::ICEApplication::SetTerminationHandler(CustomTermHandler);
// This is optional
// Logger Information
ShowLogger();
ICEngine::StartApplication();
return 0;
}
void ShowLogger() {
// The logger needs to be initialized before you can use it.
// This will be done by the engine, NEVER the user.
ICEngine::Log::Init();
// Before using the logger macros, you may want to configure logging options such as log levels and output streams.
// By default, the logger outputs to std::cout, but you can add more streams (e.g., files) or set the log level as needed.
// Logging Levels:
// - OFF
// - TRACE
// - DEBUG
// - WARN
// - ERROR
// - CRITICAL
// - FATAL
ICEngine::Log::GetCoreLogger()->SetLevel(ICEngine::TRACE);
ICEngine::Log::GetAppLogger()->SetLevel(ICEngine::TRACE);
// You can have multiple log streams, ie console + file etc
// You do not need to have the same streams for each logger
#include <fstream>
// Create file streams and transfer ownership to the logger
// You need to create a unique pointer, because the logger will
// take ownership of the streams and clean them up when the app
// is complete
ICEngine::Log::GetCoreLogger()->AddSink(std::make_shared<ICEngine::FileSink>("core_logs.txt"));
ICEngine::Log::GetCoreLogger()->AddSink(std::make_shared<ICEngine::ConsoleSink>());
ICEngine::Log::GetAppLogger()->AddSink(std::make_shared<ICEngine::FileSink>("app_logs.txt"));
ICEngine::Log::GetAppLogger()->AddSink(std::make_shared<ICEngine::ConsoleSink>());
// You can log multiple different types with formatting
int age = 30;
std::string module = "Network";
// CORE logger is intended for internal engine or core-level logging
// In most cases, you won't need to use CORE logging in game/application code,
// but it's available for engine-level diagnostics if necessary
CORE_LOG_TRACE("Initializing {} with age {}", module, age);
// Logs a trace-level message, useful for very detailed information
CORE_LOG_DEBUG("This is an example of a debug message");
// Logs a debug message, typically used for debugging purposes
CORE_LOG_WARN("This is an example of a warn message");
// Logs a warning, indicating a non-critical issue that should be investigated
CORE_LOG_ERROR("This is an example of an error message");
// Logs an error, signaling that something has gone wrong but the engine can still run
CORE_LOG_CRITICAL("This is an example of a critical message");
// Logs a critical issue, often indicating a major problem in the core system that needs immediate attention.
// CORE_LOG_FATAL: Logs a fatal error that crashes the application. Fatal errors in the core usually lead to dumping information into crash logs
// and stopping the program. Use with extreme caution and only in situations where the application can't recover
// CORE_LOG_FATAL("This is an example of a fatal message");
// These macros are designed for logging from your game or application code
// They allow you to monitor application flow, errors, and warnings from the perspective of the game logic or app layer
LOG_TRACE("App took longer to respond than expected: {} seconds", 2.34);
// Logs a trace message, ideal for fine-grained, verbose debugging details
LOG_DEBUG("This is an example of a debug message");
// Logs a debug message, typically used to help trace the execution during development
LOG_WARN("This is an example of a warn message");
// Logs a warning, indicating something unexpected happened, but the application can continue running
LOG_ERROR("This is an example of an error message");
// Logs an error, signaling that an issue occurred that may require attention but is not catastrophic
LOG_CRITICAL("This is an example of a critical message");
// Logs a critical message, suggesting something very wrong happened, but the program may still attempt to run
// LOG_FATAL: Logs a fatal error in the application layer. This will trigger the Fatal Handler, which you can override
// The Fatal Handler provides a mechanism for handling unrecoverable errors gracefully, allowing you to define how the application reacts to fatal crashes
// LOG_FATAL("This is an example of log fatal crash!");
}
void CustomTermHandler(const std::string &message) {
// Perform any other task here, like showing a popup warning indicating something crashed
Platform::ShowPopup("Demo App", message);
// You don't have to specify a title, it will default to ICEngine
// Platform::ShowPopup(message);
std::exit(EXIT_FAILURE); // Terminate here if you need to
}
class DemoApp : public ICEngine::ICEApplication {
public:
void Run() override {
LOG_TRACE("Running demo app!");
CORE_LOG_FATAL("Fatal error"); // This will terminate the application
LOG_TRACE("Demo app completed successfully!"); // Therefore this will not run
}
};
ICEngine::ICEApplication *ICEngine::CreateICEApplication() {
return new DemoApp();
}

View File

@ -0,0 +1,8 @@
//
// Created by illyum on 9/15/2024.
//
#include <ICEngine.hpp>
int main() {
}

View File

@ -0,0 +1,3 @@
mkdir build-vs
cd build-vs
cmake -G "Visual Studio 17 2022" ..

View File

@ -1,99 +0,0 @@
#include "IsoEngine.h"
#include "components.h"
#include <iostream>
#define ENABLE_LOGGING
enum class MenuState {
MAIN_MENU,
OPTIONS,
QUIT
};
int main() {
int screenWidth = 800;
int screenHeight = 600;
IsoEngine engine(screenWidth, screenHeight, nullptr);
engine.Initialize();
SceneManager& sceneManager = engine.GetSceneManager();
entt::entity mainMenuScene = sceneManager.CreateScene();
auto& registry = engine.GetRegistry();
// Button dimensions
float buttonWidth = 200.0f;
float buttonHeight = 50.0f;
float spacing = 20.0f; // Vertical spacing between buttons
// Center X position
float centerX = screenWidth / 2 - buttonWidth / 2;
// Y positions for each button
float singlePlayerY = screenHeight / 2 - (buttonHeight + spacing);
float quitButtonY = screenHeight / 2 + (buttonHeight + spacing);
// Create a UI button for "Single Player"
entt::entity singlePlayerButton = registry.create();
registry.emplace<TransformComponent>(singlePlayerButton, centerX, singlePlayerY, 1.0f, 1.0f, 0.0f); // Centered horizontally
registry.emplace<UIComponent>(singlePlayerButton, "Single Player", buttonWidth, buttonHeight, [&]() {
std::cout << "Single Player button clicked!" << std::endl;
});
registry.emplace<LayerComponent>(singlePlayerButton, 1); // Main menu on layer 1
// Create a "Quit" button
entt::entity quitButton = registry.create();
registry.emplace<TransformComponent>(quitButton, centerX, quitButtonY, 1.0f, 1.0f, 0.0f); // Centered horizontally
registry.emplace<UIComponent>(quitButton, "Quit", buttonWidth, buttonHeight, [&]() {
engine.Shutdown();
});
registry.emplace<LayerComponent>(quitButton, 1); // Also on layer 1
// Create an "F3" debug overlay on a higher layer
entt::entity debugOverlay = registry.create();
registry.emplace<TransformComponent>(debugOverlay, 10.0f, 10.0f, 1.0f, 1.0f, 0.0f); // Placed at top-left corner
registry.emplace<UIComponent>(debugOverlay, "FPS: 60\nPosition: (100, 200)", 300.0f, 100.0f, nullptr);
registry.emplace<LayerComponent>(debugOverlay, 2); // Debug overlay on layer 2
// Set active scene to the main menu
sceneManager.SetActiveScene(mainMenuScene);
// Run the engine loop
engine.Run();
engine.Shutdown();
return 0;
}
// entt::entity gameScene = sceneManager.CreateScene();
// sceneManager.SetActiveScene(gameScene);
//
// entt::entity player = engine.GetRegistry().create();
// engine.GetRegistry().emplace<TransformComponent>(player, 400.0f, 300.0f, 1.0f, 1.0f, 0.0f);
//
// auto& inputComponent = engine.GetRegistry().emplace<InputComponent>(player);
//
// inputComponent.BindKey(InputAction::MOVE_UP, KEY_W);
// inputComponent.BindKey(InputAction::MOVE_DOWN, KEY_S);
// inputComponent.BindKey(InputAction::MOVE_LEFT, KEY_A);
// inputComponent.BindKey(InputAction::MOVE_RIGHT, KEY_D);
//
// inputComponent.SetActionCallback(InputAction::MOVE_UP, [&]() {
// auto& transform = engine.GetRegistry().get<TransformComponent>(player);
// transform.y -= 5.0f;
// });
// inputComponent.SetActionCallback(InputAction::MOVE_DOWN, [&]() {
// auto& transform = engine.GetRegistry().get<TransformComponent>(player);
// transform.y += 5.0f;
// });
// inputComponent.SetActionCallback(InputAction::MOVE_LEFT, [&]() {
// auto& transform = engine.GetRegistry().get<TransformComponent>(player);
// transform.x -= 5.0f;
// });
// inputComponent.SetActionCallback(InputAction::MOVE_RIGHT, [&]() {
// auto& transform = engine.GetRegistry().get<TransformComponent>(player);
// transform.x += 5.0f;
// });

View File

@ -1,4 +0,0 @@
int main() {
return 0;
}

View File

@ -1,19 +0,0 @@
//
// Created by illyum on 9/13/2024.
//
#ifndef FATALHANDLER_H
#define FATALHANDLER_H
#include <IsoEnginePCH.h>
// TODO: Implement warning popup/crash handler (platform specific)
// TODO: Separate fatal handlers for core (the engine) and app (the user's app)
// maybe let the user handle their own fatal errors if they so choose, or they can use the default? similar
// to how the user has to specify an engine application
namespace IsoEngine {
void FatalHandler(const std::string& message);
};
#endif //FATALHANDLER_H

View File

@ -1,68 +0,0 @@
#include "IsoEngine.h"
#include <Logger.h>
#include "components.h"
#include <raylib.h>
IsoEngine::IsoEngine(int screenWidth, int screenHeight, Network* network)
: screenWidth(screenWidth), screenHeight(screenHeight), network(network), sceneManager(registry) {}
IsoEngine::~IsoEngine() {
Shutdown();
}
void IsoEngine::Initialize() {
InitWindow(screenWidth, screenHeight, "IsoEngine Game");
SetTargetFPS(60);
if (network) {
network->Initialize();
}
Logger::GetCoreLogger().AddOutputStream(&std::cout);
Logger::GetAppLogger().AddOutputStream(&std::cout);
CORE_LOG_INFO("Engine initialized!");
}
void IsoEngine::Run() {
while (isRunning && !WindowShouldClose()) {
Update();
Render();
if (network) {
network->ReceiveData();
}
}
}
void IsoEngine::Shutdown() {
sceneManager.RenderActiveScene();
CloseWindow();
if (network) {
network->Shutdown();
}
CORE_LOG_INFO("Engine shut down");
}
void IsoEngine::Update() {
if (IsKeyPressed(KEY_ESCAPE)) {
isRunning = false;
}
sceneManager.UpdateActiveScene(GetFrameTime());
sceneManager.UpdateUI(registry);
}
void IsoEngine::Render() {
BeginDrawing();
ClearBackground(RAYWHITE);
sceneManager.RenderActiveScene();
DrawText("IsoEngine Running!", 10, 10, 20, DARKGRAY);
sceneManager.RenderUI(registry);
DrawFPS(10, 100);
EndDrawing();
}

View File

@ -1,30 +0,0 @@
#pragma once
#include <entt/entt.hpp>
#include "network.h"
#include "scene_manager.h"
class IsoEngine {
public:
IsoEngine(int screenWidth, int screenHeight, Network* network);
~IsoEngine();
void Initialize();
void Run();
void Shutdown();
SceneManager& GetSceneManager() { return sceneManager; }
entt::registry& GetRegistry() { return registry; }
private:
void Update();
void Render();
bool isRunning = true;
int screenWidth;
int screenHeight;
Network* network;
entt::registry registry;
SceneManager sceneManager;
};

View File

@ -1,28 +0,0 @@
//
// Created by illyum on 9/12/2024.
//
#ifndef ISOENGINEPCH_H
#define ISOENGINEPCH_H
// #ifdef WIN32
// #include <Windows.h>
// #endif
#include <string>
#include <memory>
#include <vector>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <functional>
#include <fstream>
#include <ctime>
#include <deque>
#include <mutex>
#include <format>
#endif //ISOENGINEPCH_H

View File

@ -1,63 +0,0 @@
#include "Logger.h"
#include "FatalHandler.h"
Logger& Logger::GetCoreLogger() {
static Logger coreLogger;
return coreLogger;
}
Logger& Logger::GetAppLogger() {
static Logger appLogger;
return appLogger;
}
Logger::Logger() {}
void Logger::AddOutputStream(std::ostream* stream) {
outputStreams.push_back(stream);
}
void Logger::SetLogLevel(LogLevel level) {
logLevel = level;
}
void Logger::Log(LogLevel level, const std::string& message) {
if (level >= logLevel) {
LogInternal(level, message);
}
}
void Logger::LogInternal(LogLevel level, const std::string& message) {
std::string time = GetCurrentTime();
std::string levelStr = LevelToString(level);
for (auto* stream : outputStreams) {
*stream << time << " [" << levelStr << "]: " << message << std::endl;
}
}
std::string Logger::GetCurrentTime() {
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&in_time_t), "%Y/%m/%d %H:%M:%S");
return ss.str();
}
std::string Logger::LevelToString(LogLevel level) {
switch (level) {
case LogLevel::TRACE_l: return "TRACE";
case LogLevel::DEBUG_l: return "DEBUG";
case LogLevel::INFO_l: return "INFO";
case LogLevel::WARN_l: return "WARN";
case LogLevel::ERROR_l: return "ERROR";
case LogLevel::FATAL_l: return "FATAL";
default: return "UNKNOWN";
}
}
template<typename... Args>
void Logger::FatalHandler(const std::string& format, Args... args) {
IsoEngine::FatalHandler(format, args...);
}

View File

@ -1,77 +0,0 @@
#pragma once
#include <IsoEnginePCH.h>
enum class LogLevel {
TRACE_l,
DEBUG_l,
INFO_l,
WARN_l,
ERROR_l,
FATAL_l
};
class Logger {
public:
static Logger& GetCoreLogger();
static Logger& GetAppLogger();
void Log(LogLevel level, const std::string& message);
template<typename... Args>
void LogFormat(LogLevel level, const std::string& format, Args&&... args) {
if (level >= logLevel) {
std::string formattedMessage = std::vformat(format, std::make_format_args(std::forward<Args>(args)...));
LogInternal(level, formattedMessage);
}
}
void AddOutputStream(std::ostream* stream);
void SetLogLevel(LogLevel level);
template<typename... Args>
static void FatalHandler(const std::string& format, Args... args);
private:
Logger();
void LogInternal(LogLevel level, const std::string& message);
std::string GetCurrentTime();
std::string LevelToString(LogLevel level);
std::vector<std::ostream*> outputStreams;
LogLevel logLevel = LogLevel::TRACE_l;
};
#ifdef ENABLE_LOGGING
#define LOG_TRACE(...) Logger::GetAppLogger().LogFormat(LogLevel::TRACE_l, __VA_ARGS__)
#define LOG_DEBUG(...) Logger::GetAppLogger().LogFormat(LogLevel::DEBUG_l, __VA_ARGS__)
#define LOG_INFO(...) Logger::GetAppLogger().LogFormat(LogLevel::INFO_l, __VA_ARGS__)
#define LOG_WARN(...) Logger::GetAppLogger().LogFormat(LogLevel::WARN_l, __VA_ARGS__)
#define LOG_ERROR(...) Logger::GetAppLogger().LogFormat(LogLevel::ERROR_l, __VA_ARGS__)
#define LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
#define CORE_LOG_TRACE(...) Logger::GetCoreLogger().LogFormat(LogLevel::TRACE_l, __VA_ARGS__)
#define CORE_LOG_DEBUG(...) Logger::GetCoreLogger().LogFormat(LogLevel::DEBUG_l, __VA_ARGS__)
#define CORE_LOG_INFO(...) Logger::GetCoreLogger().LogFormat(LogLevel::INFO_l, __VA_ARGS__)
#define CORE_LOG_WARN(...) Logger::GetCoreLogger().LogFormat(LogLevel::WARN_l, __VA_ARGS__)
#define CORE_LOG_ERROR(...) Logger::GetCoreLogger().LogFormat(LogLevel::ERROR_l, __VA_ARGS__)
#define CORE_LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
#else
#define LOG_TRACE(...)
#define LOG_DEBUG(...)
#define LOG_INFO(...)
#define LOG_WARN(...)
#define LOG_ERROR(...)
#define LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
#define CORE_LOG_TRACE(...)
#define CORE_LOG_DEBUG(...)
#define CORE_LOG_INFO(...)
#define CORE_LOG_WARN(...)
#define CORE_LOG_ERROR(...)
#define CORE_LOG_FATAL(...) Logger::FatalHandler(__VA_ARGS__)
#endif

View File

@ -1,10 +0,0 @@
#pragma once
#include "components/sprite_component.h"
#include "components/scene_component.h"
#include "components/transform_component.h"
#include "components/health_component.h"
#include "components/input_component.h"
#include "components/physics_component.h"
#include "components/ui_component.h"
#include "components/layer_component.h"

View File

@ -1,8 +0,0 @@
#pragma once
struct HealthComponent {
int currentHealth;
int maxHealth;
HealthComponent(int max) : maxHealth(max), currentHealth(max) {}
};

View File

@ -1,20 +0,0 @@
#include "input_component.h"
#include <raylib.h>
void InputComponent::BindKey(InputAction action, int key) {
keyBindings[action] = key;
}
void InputComponent::Update() {
for (const auto& [action, key] : keyBindings) {
if (IsKeyDown(key)) {
if (actionCallbacks.find(action) != actionCallbacks.end()) {
actionCallbacks[action]();
}
}
}
}
void InputComponent::SetActionCallback(InputAction action, std::function<void()> callback) {
actionCallbacks[action] = std::move(callback);
}

View File

@ -1,23 +0,0 @@
#pragma once
enum class InputAction {
MOVE_UP,
MOVE_DOWN,
MOVE_LEFT,
MOVE_RIGHT,
};
class InputComponent {
public:
InputComponent() = default;
void BindKey(InputAction action, int key);
void Update();
void SetActionCallback(InputAction action, std::function<void()> callback);
private:
std::unordered_map<InputAction, int> keyBindings;
std::unordered_map<InputAction, std::function<void()>> actionCallbacks;
};

View File

@ -1,7 +0,0 @@
#pragma once
struct LayerComponent {
int layer;
LayerComponent(int layer = 0) : layer(layer) {}
};

View File

@ -1,6 +0,0 @@
#include "physics_component.h"
void PhysicsComponent::Update(float deltaTime) {
velocityX += accelerationX * deltaTime;
velocityY += accelerationY * deltaTime;
}

View File

@ -1,10 +0,0 @@
#pragma once
struct PhysicsComponent {
float velocityX = 0.0f;
float velocityY = 0.0f;
float accelerationX = 0.0f;
float accelerationY = 0.0f;
void Update(float deltaTime);
};

View File

@ -1 +0,0 @@
#include "scene_component.h"

View File

@ -1,5 +0,0 @@
#pragma once
struct SceneComponent {
bool isActive;
};

View File

@ -1,18 +0,0 @@
#include "sprite_component.h"
#include <raylib.h>
#include "Logger.h"
#include "transform_component.h"
void SpriteComponent::Render(float x, float y) const {
if (texture) {
DrawTexture(*reinterpret_cast<Texture2D*>(texture), x, y, WHITE);
}
}
void SpriteComponent::Render(TransformComponent transform) const {
if (texture) {
DrawTexture(*reinterpret_cast<Texture2D*>(texture), transform.x, transform.y, WHITE);
}
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "transform_component.h"
struct SpriteComponent {
public:
void* texture; // void* to abstract Texture2D
void Render(float x, float y) const;
void Render(TransformComponent transform) const;
};
// Usage:
// SpriteComponent sprite;
// sprite.texture = static_cast<void*>(&your_texture);

View File

@ -1,11 +0,0 @@
#pragma once
class TransformComponent {
public:
float x = 0.0f;
float y = 0.0f;
float scaleX = 1.0f;
float scaleY = 1.0f;
float rotation = 0.0f;
};

View File

@ -1,5 +0,0 @@
//
// Created by illyum on 9/12/2024.
//
#include "ui_component.h"

View File

@ -1,18 +0,0 @@
#pragma once
enum class UIState {
NORMAL,
HOVERED,
CLICKED
};
struct UIComponent {
std::string text;
float width;
float height;
std::function<void()> onClick;
UIState state = UIState::NORMAL;
UIComponent(std::string text, float width, float height, std::function<void()> onClick)
: text(std::move(text)), width(width), height(height), onClick(std::move(onClick)) {}
};

View File

@ -1,64 +0,0 @@
#include "network.h"
#include <enet.h>
#include "Logger.h"
class ENetClient : public Network {
public:
ENetClient() : client(nullptr), peer(nullptr) {}
void Initialize() override {
if (enet_initialize() != 0) {
CORE_LOG_FATAL("An error occurred while initializing ENet");
throw std::runtime_error("An error occurred while initializing ENet");
}
client = enet_host_create(nullptr, 1, 2, 0, 0);
if (!client) {
CORE_LOG_FATAL("An error occurred while creating the ENet client");
throw std::runtime_error("An error occurred while initializing ENet Client");
}
ENetAddress address;
enet_address_set_host(&address, "localhost");
address.port = 1234;
peer = enet_host_connect(client, &address, 2, 0);
if (!peer) {
CORE_LOG_ERROR("No available peers for initiating connection");
}
CORE_LOG_TRACE("ENet client initialized and connected to server");
}
void Shutdown() override {
if (peer) {
enet_peer_disconnect(peer, 0);
CORE_LOG_TRACE("Disconnected from peer");
}
enet_host_destroy(client);
enet_deinitialize();
CORE_LOG_TRACE("ENet client shut down");
}
void SendData(const void* data, size_t size) override {
if (peer) {
ENetPacket* packet = enet_packet_create(data, size, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(peer, 0, packet);
CORE_LOG_TRACE("Data sent to server");
}
}
void ReceiveData() override {
ENetEvent event;
while (enet_host_service(client, &event, 0) > 0) {
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
CORE_LOG_TRACE("Received packet: {}", std::string(reinterpret_cast<const char*>(event.packet->data)));
enet_packet_destroy(event.packet);
}
}
}
private:
ENetHost* client;
ENetPeer* peer;
};

View File

@ -1,48 +0,0 @@
#include "network.h"
#include <enet.h>
class ENetServer : public Network {
public:
ENetServer() : server(nullptr) {}
void Initialize() override {
if (enet_initialize() != 0) {
std::cerr << "An error occurred while initializing ENet.\n";
exit(EXIT_FAILURE);
}
ENetAddress address;
address.host = ENET_HOST_ANY;
address.port = 1234;
server = enet_host_create(&address, 32, 2, 0, 0);
if (!server) {
std::cerr << "An error occurred while trying to create the server.\n";
exit(EXIT_FAILURE);
}
}
void Shutdown() override {
enet_host_destroy(server);
enet_deinitialize();
}
void SendData(const void* data, size_t size) override {
ENetPacket* packet = enet_packet_create(data, size, ENET_PACKET_FLAG_RELIABLE);
enet_host_broadcast(server, 0, packet);
}
void ReceiveData() override {
ENetEvent event;
while (enet_host_service(server, &event, 0) > 0) {
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
std::cout << "Received packet from client: " << event.packet->data << "\n";
enet_packet_destroy(event.packet);
}
}
}
private:
ENetHost* server;
};

View File

@ -1,193 +0,0 @@
//
// Created by illyum on 9/13/2024.
//
#include "filepacker.h"
#include "Logger.h"
bool FilePacker::Pack(const std::string &directoryPath, const std::string &outputBapFile) {
BapHeader header;
std::ofstream outputFile(outputBapFile, std::ios::binary);
if (!outputFile) {
CORE_LOG_ERROR("Failed to open output file");
return false;
}
std::memcpy(header.magic, static_cast<const char*>("BAP"), 3);
header.version = PACKER_VERSION;
header.fileCount = 0;
std::vector<std::pair<FileEntry, std::vector<char>>> filesData;
size_t headerSize = 3 + sizeof(header.version) + sizeof(header.fileCount);
for (const auto& entry : std::filesystem::directory_iterator(directoryPath)) {
if (entry.is_regular_file()) {
FileEntry fileEntry;
fileEntry.filePath = entry.path().string();
// TODO: Implement filetype detection
fileEntry.fileType = RAWBINARY;
fileEntry.compressedSize = COMPRESSION_NONE;
std::ifstream inputFile(entry.path(), std::ios::binary | std::ios::ate);
if (!inputFile) {
CORE_LOG_ERROR("FilePacker::Pack(): Failed to open file for packing: {}", entry.path().string());
return false;
}
fileEntry.dataSize = inputFile.tellg();
inputFile.seekg(0, std::ios::beg);
std::vector<char> fileData(fileEntry.dataSize);
inputFile.read(fileData.data(), fileEntry.dataSize);
inputFile.close();
// TODO: Implement data compression
std::vector<char> compressedData = CompressData(fileData, fileEntry.compression);
fileEntry.compressedSize = compressedData.size();
filesData.emplace_back(fileEntry, std::move(compressedData));
size_t pathLength = fileEntry.filePath.size();
size_t metadataLength = fileEntry.metadata.size();
headerSize += sizeof(pathLength) + pathLength + sizeof(fileEntry.fileType) + sizeof(fileEntry.compression)
+ sizeof(fileEntry.dataSize) + sizeof(fileEntry.compressedSize) + sizeof(fileEntry.dataOffset)
+ sizeof(metadataLength) + metadataLength;
header.fileEntries.push_back(fileEntry);
header.fileCount++;
}
}
outputFile.seekp(headerSize, std::ios::beg);
for (size_t i = 0; i < filesData.size(); ++i) {
auto& fileEntry = header.fileEntries[i];
const auto& compressedData = filesData[i].second;
fileEntry.dataOffset = outputFile.tellp();
outputFile.write(compressedData.data(), compressedData.size());
}
outputFile.seekp(0, std::ios::beg);
WriteHeader(outputFile, header);
outputFile.close();
return true;
}
std::vector<FileEntry> FilePacker::listFiles(const std::string& bapFile) {
std::ifstream inputFile(bapFile, std::ios::binary);
if (!inputFile) {
CORE_LOG_FATAL("Failed to open .bap file for listing: {}", bapFile);
throw std::runtime_error("File could not be opened");
}
BapHeader header = ReadHeader(inputFile);
inputFile.close();
return header.fileEntries;
}
bool FilePacker::ExtractFile(const std::string& bapFile, const std::string& fileName, const std::string& outputPath) {
std::ifstream inputFile(bapFile, std::ios::binary);
if (!inputFile) {
CORE_LOG_ERROR("Failed to open .bap file for extraction: {}", bapFile);
return false;
}
BapHeader header = ReadHeader(inputFile);
for (const auto& fileEntry : header.fileEntries) {
if (fileEntry.filePath == fileName) {
std::ofstream outFile(outputPath, std::ios::binary);
if (!outFile) {
CORE_LOG_ERROR("Failed to create output file: {}", outputPath);
return false;
}
std::vector<char> compressedData(fileEntry.compressedSize);
inputFile.seekg(fileEntry.dataOffset, std::ios::beg);
inputFile.read(compressedData.data(), compressedData.size());
std::vector<char> decompressedData = DecompressData(compressedData, fileEntry.compression);
outFile.write(decompressedData.data(), decompressedData.size());
outFile.close();
return true;
}
}
CORE_LOG_ERROR("File not found in .bap archive: {}", fileName);
return false;
}
void FilePacker::WriteHeader(std::ofstream& outFile, const BapHeader& header) {
outFile.write(header.magic, 3);
outFile.write(reinterpret_cast<const char*>(&header.version), sizeof(header.version));
outFile.write(reinterpret_cast<const char*>(&header.fileCount), sizeof(header.fileCount));
for (const auto& fileEntry : header.fileEntries) {
size_t pathLength = fileEntry.filePath.size();
outFile.write(reinterpret_cast<const char*>(&pathLength), sizeof(pathLength));
outFile.write(fileEntry.filePath.c_str(), pathLength);
outFile.write(reinterpret_cast<const char*>(&fileEntry.fileType), sizeof(fileEntry.fileType));
outFile.write(reinterpret_cast<const char*>(&fileEntry.compression), sizeof(fileEntry.compression));
outFile.write(reinterpret_cast<const char*>(&fileEntry.dataSize), sizeof(fileEntry.dataSize));
outFile.write(reinterpret_cast<const char*>(&fileEntry.compressedSize), sizeof(fileEntry.compressedSize));
outFile.write(reinterpret_cast<const char*>(&fileEntry.dataOffset), sizeof(fileEntry.dataOffset));
size_t metadataLength = fileEntry.metadata.size();
outFile.write(reinterpret_cast<const char*>(&metadataLength), sizeof(metadataLength));
outFile.write(fileEntry.metadata.c_str(), metadataLength);
}
}
BapHeader FilePacker::ReadHeader(std::ifstream& inFile) {
BapHeader header;
inFile.read(header.magic, 3);
inFile.read(reinterpret_cast<char*>(&header.version), sizeof(header.version));
inFile.read(reinterpret_cast<char*>(&header.fileCount), sizeof(header.fileCount));
if (header.version != PACKER_VERSION) {
CORE_LOG_FATAL("FilePacker::ReadHeader(): Wrong .bap file version.");
throw std::runtime_error("Invalid bap file version");
}
for (int i = 0; i < header.fileCount; ++i) {
FileEntry fileEntry;
size_t pathLength;
inFile.read(reinterpret_cast<char*>(&pathLength), sizeof(pathLength));
fileEntry.filePath.resize(pathLength);
inFile.read(fileEntry.filePath.data(), pathLength);
inFile.read(reinterpret_cast<char*>(&fileEntry.fileType), sizeof(fileEntry.fileType));
inFile.read(reinterpret_cast<char*>(&fileEntry.compression), sizeof(fileEntry.compression));
inFile.read(reinterpret_cast<char*>(&fileEntry.dataSize), sizeof(fileEntry.dataSize));
inFile.read(reinterpret_cast<char*>(&fileEntry.compressedSize), sizeof(fileEntry.compressedSize));
inFile.read(reinterpret_cast<char*>(&fileEntry.dataOffset), sizeof(fileEntry.dataOffset));
size_t metadataLength;
inFile.read(reinterpret_cast<char*>(&metadataLength), sizeof(metadataLength));
fileEntry.metadata.resize(metadataLength);
inFile.read(fileEntry.metadata.data(), metadataLength);
header.fileEntries.push_back(fileEntry);
}
return header;
}
std::vector<char> FilePacker::CompressData(const std::vector<char>& input, CompressionType compression) {
// IMPL: Implement actual compression on a per file basis
if (compression == COMPRESSION_NONE) {
return input;
}
return input;
}
std::vector<char> FilePacker::DecompressData(const std::vector<char>& input, CompressionType compression) {
// IMPL: Implement decompression on a per file basis
if (compression == COMPRESSION_NONE) {
return input;
}
return input;
}

View File

@ -1,55 +0,0 @@
//
// Created by illyum on 9/13/2024.
//
#ifndef FILEPACKER_H
#define FILEPACKER_H
#include <IsoEnginePCH.h>
#define BAP_MAGIC "BAP"
#define PACKER_VERSION 1
enum CompressionType {
COMPRESSION_NONE,
COMPRESSION_LZMA
};
enum FileType {
PNG,
RAWTEXT,
RAWBINARY
};
struct FileEntry {
std::string filePath;
FileType fileType;
CompressionType compression;
size_t dataSize;
size_t compressedSize;
std::string metadata;
size_t dataOffset;
};
struct BapHeader {
char magic[3];
int version;
int fileCount;
std::vector<FileEntry> fileEntries;
};
class FilePacker {
public:
bool Pack(const std::string& directoryPath, const std::string& outputBapFile);
bool Unpack(const std::string& bapFile, const std::string& outputDirectory);
std::vector<FileEntry> listFiles(const std::string& bapFile);
bool ExtractFile(const std::string& bapFile, const std::string& fileName, const std::string& outputPath);
private:
void WriteHeader(std::ofstream& outFile, const BapHeader& header);
BapHeader ReadHeader(std::ifstream& inFile);
std::vector<char> CompressData(const std::vector<char>& input, CompressionType compression);
std::vector<char> DecompressData(const std::vector<char>& input, CompressionType compression);
};
#endif //FILEPACKER_H

View File

@ -1,14 +0,0 @@
#pragma once
#define SERVER_PORT 6771
#define SERVER_ADDRESS "127.0.0.1"
class Network {
public:
virtual void Initialize() = 0;
virtual void Shutdown() = 0;
virtual void SendData(const void* data, size_t size) = 0;
virtual void ReceiveData() = 0;
virtual ~Network() = default;
};

View File

@ -1,38 +0,0 @@
//
// Created by illyum on 9/13/2024.
//
#include "FatalHandler.h"
#include <execinfo.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include <format>
namespace IsoEngine {
template<typename... Args>
void FatalHandler(const std::string& format, Args... args) {
std::ostringstream stream;
stream << std::format(format, args...);
// TODO: change the name of the file to reflect the time the crash happened
std::ofstream crashFile("crash.log", std::ios::app);
crashFile << "FATAL ERROR: " << stream.str() << std::endl;
void* callstack[128];
int frames = backtrace(callstack, 128);
char** symbols = backtrace_symbols(callstack, frames);
crashFile << "Stack trace:\n";
for (int i = 0; i < frames; ++i) {
crashFile << symbols[i] << std::endl;
}
free(symbols);
crashFile.close();
std::abort();
}
}

View File

@ -1,64 +0,0 @@
//
// Created by illyum on 9/13/2024.
//
#include "FatalHandler.h"
#include <windows.h>
#include <dbghelp.h>
#include <fstream>
#include <sstream>
#include <format>
#pragma comment(lib, "dbghelp.lib")
namespace IsoEngine {
template<typename... Args>
void FatalHandler(const std::string &format, Args... args) {
std::ostringstream stream;
stream << std::format(format, args...);
// TODO: change the name of the file to reflect the time the crash happened
std::ofstream crashFile("crash.log", std::ios::app);
crashFile << "FATAL ERROR: " << stream.str() << std::endl;
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
CONTEXT context;
RtlCaptureContext(&context);
STACKFRAME64 stackFrame = {};
stackFrame.AddrPC.Offset = context.Rip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = context.Rbp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = context.Rsp;
stackFrame.AddrStack.Mode = AddrModeFlat;
crashFile << "Stack trace:\n";
while (StackWalk64(IMAGE_FILE_MACHINE_AMD64, process, GetCurrentThread(), &stackFrame, &context, NULL,
SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
DWORD64 address = stackFrame.AddrPC.Offset;
if (address == 0) {
break;
}
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO) buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 displacement = 0;
if (SymFromAddr(process, address, &displacement, symbol)) {
crashFile << symbol->Name << " - 0x" << std::hex << symbol->Address << std::dec << "\n";
} else {
crashFile << "Unresolved symbol at address: 0x" << std::hex << address << std::dec << "\n";
}
}
SymCleanup(process);
crashFile.close();
std::abort();
}
}

View File

@ -1,110 +0,0 @@
#include "scene_manager.h"
#include "Logger.h"
#include "raylib.h"
SceneManager::SceneManager(entt::registry& registry) : registry(registry), activeScene(entt::null) {}
void SceneManager::SetActiveScene(entt::entity scene) {
if (activeScene != entt::null) {
auto& currentScene = registry.get<SceneComponent>(activeScene);
currentScene.isActive = false;
}
activeScene = scene;
auto& newScene = registry.get<SceneComponent>(activeScene);
newScene.isActive = true;
}
entt::entity SceneManager::CreateScene() {
entt::entity scene = registry.create();
registry.emplace<SceneComponent>(scene, false);
return scene;
}
void SceneManager::UpdateActiveScene(float delta) {
if (activeScene != entt::null) {
// Iterate over entities in the active scene that have an InputComponent
auto view = registry.view<InputComponent>();
for (auto entity : view) {
auto& inputComponent = view.get<InputComponent>(entity);
inputComponent.Update(); // This will call the input logic
}
}
}
void SceneManager::RenderActiveScene() {
if (activeScene != entt::null) {
// Create a multimap to store entities sorted by layer
std::multimap<int, entt::entity> layeredEntities;
// Gather all entities with a LayerComponent
auto view = registry.view<LayerComponent, SpriteComponent, TransformComponent>();
for (auto entity : view) {
auto& layer = view.get<LayerComponent>(entity);
layeredEntities.insert({ layer.layer, entity });
}
// Render all entities sorted by layer
for (auto& pair : layeredEntities) {
auto entity = pair.second;
auto& sprite = registry.get<SpriteComponent>(entity);
auto& transform = registry.get<TransformComponent>(entity);
// Render the sprite at the position defined by the TransformComponent
sprite.Render(transform);
}
}
}
void SceneManager::UpdateUI(entt::registry& registry) {
Vector2 mousePosition = GetMousePosition(); // This assumes a raylib-like GetMousePosition, adapt as needed for your system
auto view = registry.view<UIComponent, TransformComponent>();
for (auto entity : view) {
auto& ui = view.get<UIComponent>(entity);
auto& transform = view.get<TransformComponent>(entity);
// Check if the mouse is over the button
bool isHovered = (mousePosition.x > transform.x && mousePosition.x < transform.x + ui.width &&
mousePosition.y > transform.y && mousePosition.y < transform.y + ui.height);
if (isHovered) {
ui.state = IsMouseButtonPressed(MOUSE_LEFT_BUTTON) ? UIState::CLICKED : UIState::HOVERED;
// If clicked, call the onClick function
if (ui.state == UIState::CLICKED && ui.onClick) {
ui.onClick();
}
} else {
ui.state = UIState::NORMAL;
}
}
}
void SceneManager::RenderUI(entt::registry& registry) {
auto view = registry.view<UIComponent, TransformComponent>();
for (auto entity : view) {
auto& ui = view.get<UIComponent>(entity);
auto& transform = view.get<TransformComponent>(entity);
// Render the button background
Color buttonColor = DARKGRAY;
if (ui.state == UIState::HOVERED) {
buttonColor = LIGHTGRAY;
} else if (ui.state == UIState::CLICKED) {
buttonColor = GRAY;
}
// Use the raw transform position (no adjustment to center screen)
DrawRectangle(transform.x, transform.y, ui.width, ui.height, buttonColor);
// Render the button text (centered within the button)
int textWidth = MeasureText(ui.text.c_str(), 20);
int textX = transform.x + (ui.width / 2) - (textWidth / 2);
int textY = transform.y + (ui.height / 2) - 10; // Slight vertical adjustment
DrawText(ui.text.c_str(), textX, textY, 20, BLACK);
}
}

View File

@ -1,20 +0,0 @@
#pragma once
#include <entt/entt.hpp>
#include <components.h>
class SceneManager {
public:
SceneManager(entt::registry& registry);
void SetActiveScene(entt::entity scene);
entt::entity CreateScene();
void UpdateActiveScene(float delta);
void RenderActiveScene();
void UpdateUI(entt::registry& registry);
void RenderUI(entt::registry& registry);
private:
entt::registry& registry;
entt::entity activeScene;
};

6102
vendor/enet/enet.h vendored

File diff suppressed because it is too large Load Diff