Compare commits

...

5 Commits

8 changed files with 101 additions and 23 deletions

2
.gitignore vendored
View File

@ -3,4 +3,4 @@ cmake-build-debug/
.idea/
# Build folders
*build/
build*/

View File

@ -36,15 +36,19 @@ SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${ARCH_DIR}/lib)
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${ARCH_DIR}/lib)
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 ()
INCLUDE_DIRECTORIES(engine/)
SET(EngineSources
engine/src/core/test.cpp
engine/src/core/ICEApplication.cpp
)
SET(PrecompiledHeader "pch.h")

View File

@ -6,5 +6,6 @@
#define ICENGINE_HPP
#include "src/core/Logger.hpp"
#include "src/core/ICEApplication.hpp"
#endif //ICENGINE_HPP

View File

@ -8,5 +8,6 @@
#include <chrono>
#include <cstdarg>
#include <iomanip>
#include <utility>
#include <sstream>
#include <iostream>

View File

@ -0,0 +1,24 @@
//
// Created by illyum on 9/15/2024.
//
#include "ICEngine.hpp"
#include "pch.hpp"
namespace ICEngine {
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,19 @@
//
// Created by illyum on 9/15/2024.
//
#pragma once
namespace ICEngine {
class ICEApplication {
public:
ICEApplication() {}
virtual ~ICEApplication() {}
virtual void Run() = 0;
};
void StartApplication(); // Starts the application, managed by the engine.
// Application-specific function that will be defined by the user
extern ICEApplication* CreateICEApplication();
}

View File

@ -7,7 +7,6 @@
#include <pch.hpp>
namespace ICEngine {
enum LogLevel {
OFF = 0,
TRACE,
@ -22,9 +21,10 @@ namespace ICEngine {
private:
Logger(const char *name, std::ostream *stream) : name(name) {
if (stream) {
streams.push_back(stream);
streams.push_back(std::unique_ptr<std::ostream>(stream));
}
}
friend class Log;
public:
@ -32,26 +32,27 @@ namespace ICEngine {
this->level = level;
}
void AddStream(std::ostream * stream) {
this->streams.push_back(stream);
void AddStream(std::unique_ptr<std::ostream> stream) {
this->streams.push_back(std::move(stream));
}
template<typename... Args>
void Log(LogLevel level, const char *file, int line, const char *func, const std::string &formatStr, Args &&... args) {
void Log(LogLevel level, const char *file, int line, const char *func, const std::string &formatStr,
Args &&... args) {
// TODO: Create a crash handler and manage fatal messages separately (creates crashdump)
// TODO: Allow user to create their own class that inherits Fatal Handler so they can implement it themselves
if (level < this->level) return;
std::string formattedMessage = format(formatStr, std::forward<Args>(args)...);
std::string logMessage = formatMessage(level, file, line, func, formattedMessage);
for (auto stream: streams) {
for (const auto &stream: streams) {
(*stream) << logMessage << std::endl;
}
}
private:
const char *name;
std::vector<std::ostream *> streams;
std::vector<std::unique_ptr<std::ostream> > streams;
LogLevel level = DEBUG;
static const char *levelToString(LogLevel level) {
@ -95,7 +96,8 @@ namespace ICEngine {
}
template<typename T, typename... Args>
void formatHelper(std::ostringstream &oss, const std::string &formatStr, T &&firstArg, Args&&... remainingArgs) {
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);
@ -105,13 +107,14 @@ namespace ICEngine {
}
}
// Formats the log message with metadata (timestamp, file, line, etc.)
std::string formatMessage(LogLevel level, const char *file, int line, const char *func, const std::string &message) {
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 << "[" << levelToString(level) << "] ";
oss << "[" << name << "]: " << message;
oss << "[" << name << "] ";
oss << "[" << levelToString(level) << "]: ";
oss << message;
return oss.str();
}
};
@ -119,8 +122,16 @@ namespace ICEngine {
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() {
@ -135,7 +146,9 @@ namespace ICEngine {
private:
Log() = delete;
Log(const Log &) = delete;
Log &operator=(const Log &) = delete;
};

View File

@ -9,6 +9,7 @@ void ShowLogger();
int main() {
ShowLogger();
ICEngine::StartApplication();
return 0;
}
@ -34,11 +35,15 @@ void ShowLogger() {
// You can have multiple log streams, ie console + file etc
// You do not need to have the same streams for each logger
#include <fstream>
std::ofstream coreFileStream("core_logs.txt");
std::ofstream appFileStream("app_logs.txt");
// 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
auto coreFileStream = std::make_unique<std::ofstream>("core_logs.txt");
auto appFileStream = std::make_unique<std::ofstream>("app_logs.txt");
ICEngine::Log::GetCoreLogger()->AddStream(&coreFileStream);
ICEngine::Log::GetAppLogger()->AddStream(&appFileStream);
ICEngine::Log::GetCoreLogger()->AddStream(std::move(coreFileStream));
ICEngine::Log::GetAppLogger()->AddStream(std::move(appFileStream));
// You can log multiple different types with formatting
int age = 30;
@ -69,3 +74,14 @@ void ShowLogger() {
// 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!");
}
class DemoApp : public ICEngine::ICEApplication {
public:
void Run() override {
LOG_TRACE("Running demo app!");
}
};
ICEngine::ICEApplication* ICEngine::CreateICEApplication() {
return new DemoApp();
}