diff --git a/SHADE_Application/SHADE_Application.vcxproj b/SHADE_Application/SHADE_Application.vcxproj index 37c97b1c..d83a0c64 100644 --- a/SHADE_Application/SHADE_Application.vcxproj +++ b/SHADE_Application/SHADE_Application.vcxproj @@ -60,7 +60,7 @@ SBpch.h Level4 _DEBUG;%(PreprocessorDefinitions) - .;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories) + ..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories) EditAndContinue Disabled false @@ -80,7 +80,7 @@ SBpch.h Level4 _RELEASE;%(PreprocessorDefinitions) - .;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories) + ..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories) Full true true diff --git a/SHADE_Application/SHADE_Application.vcxproj.filters b/SHADE_Application/SHADE_Application.vcxproj.filters new file mode 100644 index 00000000..1234632d --- /dev/null +++ b/SHADE_Application/SHADE_Application.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {D9DE78AF-4594-F1A4-CE88-EB7B3A3DE8A8} + + + {86EEB3D0-7290-DEA6-5B4B-F2FA478C65F7} + + + + + Application + + + + Scenes + + + + + Application + + + + Scenes + + + + \ No newline at end of file diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua index 60a87928..35440432 100644 --- a/SHADE_Application/premake5.lua +++ b/SHADE_Application/premake5.lua @@ -21,8 +21,7 @@ project "SHADE_Application" includedirs { - "%{IncludeDir.GLFW}", - "%{IncludeDir.GLAD}", + "%{IncludeDir.spdlog}/include", "../SHADE_Engine/src", "src" } diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 58aded2b..c420a37f 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -15,6 +15,8 @@ namespace Sandbox bool paused = false; void SBApplication::Initialize(void) { + + #ifdef SHEDITOR #else #endif diff --git a/SHADE_Application/src/WinMain.cpp b/SHADE_Application/src/WinMain.cpp index 89005432..50be1289 100644 --- a/SHADE_Application/src/WinMain.cpp +++ b/SHADE_Application/src/WinMain.cpp @@ -1,5 +1,7 @@ #include "SBpch.h" #include +#include +#include #include "Application/SBApplication.h" @@ -15,15 +17,35 @@ #define DBG_NEW new #endif -INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - PSTR lpCmdLine, INT nCmdShow) +INT WINAPI WinMain +( + _In_ HINSTANCE /*hInstance*/, + _In_opt_ HINSTANCE /*hPrevInstance*/, + _In_ PSTR /*lpCmdLine*/, + _In_ INT /*nCmdShow*/ +) { - #ifndef SHEDITOR - ShowWindow(::GetConsoleWindow(), SW_HIDE); - #endif + const SHADE::SHLogger::Config LOGGER_CONFIG{ .directoryPath = "./logs/" }; + SHADE::SHLogger::Initialise(LOGGER_CONFIG); - SHADE::SHEngine::Run(); - _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + try + { + #ifndef SHEDITOR + //ShowWindow(::GetConsoleWindow(), SW_HIDE); + #endif + + SHLOG_INFO("sup") + + SHADE::SHEngine::Run(); + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + } + catch(...) + { + SHADE::SHExceptionHandler::HandleException(std::current_exception()); + SHADE::SHLogger::Shutdown(); + } + + SHADE::SHLogger::Shutdown(); return 0; } \ No newline at end of file diff --git a/SHADE_Engine/SHADE_Engine.vcxproj b/SHADE_Engine/SHADE_Engine.vcxproj index 15d38e26..dcc0f3c8 100644 --- a/SHADE_Engine/SHADE_Engine.vcxproj +++ b/SHADE_Engine/SHADE_Engine.vcxproj @@ -117,9 +117,12 @@ + - + + + @@ -129,10 +132,13 @@ - Create + + + + @@ -157,4 +163,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/SHADE_Engine/SHADE_Engine.vcxproj.filters b/SHADE_Engine/SHADE_Engine.vcxproj.filters index 02a36cbf..8d62d05b 100644 --- a/SHADE_Engine/SHADE_Engine.vcxproj.filters +++ b/SHADE_Engine/SHADE_Engine.vcxproj.filters @@ -19,6 +19,15 @@ {B3E3FAFD-9FDD-2350-884A-BA6074E389BC} + + {AC05897C-983C-8A0D-4129-70102D3F060F} + + + {B3F7140E-1F0C-3DBF-E88D-E01E546139F0} + + + {16CF2D0E-82E3-55BF-4B65-F91EB73852F0} + @@ -63,10 +72,25 @@ Engine + + Meta + - - - + + Scene + + + Scene + + + Tools + + + Tools + + + Tools + @@ -91,6 +115,17 @@ Engine - + + Scene + + + Tools + + + Tools + + + Tools + \ No newline at end of file diff --git a/SHADE_Engine/src/SHpch.cpp b/SHADE_Engine/src/SHpch.cpp index a7fec85b..2a36c693 100644 --- a/SHADE_Engine/src/SHpch.cpp +++ b/SHADE_Engine/src/SHpch.cpp @@ -1 +1,10 @@ +/**************************************************************************************** + * \file SHpch.h + * \brief Empty source file for generating SHADE Engine's precompiled header. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + #include "SHpch.h" \ No newline at end of file diff --git a/SHADE_Engine/src/SHpch.h b/SHADE_Engine/src/SHpch.h index e69de29b..19bd69b6 100644 --- a/SHADE_Engine/src/SHpch.h +++ b/SHADE_Engine/src/SHpch.h @@ -0,0 +1,12 @@ +/**************************************************************************************** + * \file SHpch.h + * \brief Precompiled header file for SHADE Engine. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHException.cpp b/SHADE_Engine/src/Tools/SHException.cpp new file mode 100644 index 00000000..a5d08b18 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHException.cpp @@ -0,0 +1,51 @@ +/**************************************************************************************** + * \file SHException.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for custom exception types of SHADE Engine. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHException.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHException::SHException(std::string msg, const std::source_location& src) noexcept + : message { std::move(msg) } + , origin { src } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const char* SHException::what() const noexcept + { + std::stringstream ss; + ss << "SHException " << GetOriginString(); + message = ss.str(); + + return message.c_str(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + std::string SHException::GetOriginString() const noexcept + { + std::stringstream ss; + ss << "[" << origin.file_name() << ", " << origin.line() << "]"; + return ss.str(); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHException.h b/SHADE_Engine/src/Tools/SHException.h new file mode 100644 index 00000000..251217eb --- /dev/null +++ b/SHADE_Engine/src/Tools/SHException.h @@ -0,0 +1,84 @@ +/**************************************************************************************** + * \file SHException.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for custom exception types of SHADE Engine. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +// Project Headers +#include "SHLogger.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Concepts */ + /*-----------------------------------------------------------------------------------*/ + + template + concept IsException = std::is_base_of_v; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + /** + * @brief Base exception type thrown by SHADE Engine. + */ + class SHException : public std::exception + { + public: + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHException + ( + std::string msg = "", + const std::source_location& src = std::source_location::current() + ) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + const char* what() const noexcept override; + + protected: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + mutable std::string message; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + std::string GetOriginString() const noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + const std::source_location& origin; + }; +} + +#define SHASSERT(cond, msg) \ + if (!(cond)) \ + { \ + SHLOGV_CRITICAL(msg) \ + std::abort(); \ + } + diff --git a/SHADE_Engine/src/Tools/SHExceptionHandler.cpp b/SHADE_Engine/src/Tools/SHExceptionHandler.cpp new file mode 100644 index 00000000..ff6df05c --- /dev/null +++ b/SHADE_Engine/src/Tools/SHExceptionHandler.cpp @@ -0,0 +1,49 @@ +/**************************************************************************************** + * \file SHExceptionHandler.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for SHADE Engine's exception handler. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHExceptionHandler.h" + +// Project Headers +#include "SHException.h" +#include "SHLogger.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHExceptionHandler::HandleException(const std::exception_ptr& exceptionPtr) + { + try + { + // Re-throw all valid exception types + if (exceptionPtr) + { + std::rethrow_exception(exceptionPtr); + } + } + catch (const std::exception& e) + { + SHLOG_CRITICAL(e.what()) + } + catch (...) + { + // Catch any non-std::exception derived types and consider them as unknown. + SHLOG_CRITICAL("SHADE Engine has experienced an unknown fatal error!") + } + + return false; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHExceptionHandler.h b/SHADE_Engine/src/Tools/SHExceptionHandler.h new file mode 100644 index 00000000..dd1d7596 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHExceptionHandler.h @@ -0,0 +1,37 @@ +/**************************************************************************************** + * \file SHExceptionHandler.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for SHADE Engine's exception handler. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHExceptionHandler + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief Catches and logs any exceptions thrown. If the exception's type is + * SHAssertException, the application will not end unless crashOnAssert is set + * to true. + * @param exceptionPtr Pointer to the exception that was caught. + * @returns True if the application should continue running after an exception was caught. + */ + static bool HandleException(const std::exception_ptr& exceptionPtr); + }; +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHLogger.cpp b/SHADE_Engine/src/Tools/SHLogger.cpp new file mode 100644 index 00000000..7b39e979 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHLogger.cpp @@ -0,0 +1,441 @@ +/**************************************************************************************** + * \file SHLogger.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for SHADE Engine's logger. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHLogger.h" + +#include +#include + +#include +#include + +/*-------------------------------------------------------------------------------------*/ +/* Local Helper Function Declarations */ +/*-------------------------------------------------------------------------------------*/ +std::string GetDatePattern (SHADE::SHLogger::DateFormat fmt); +std::string GetClockPattern (bool is24HR); + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + unsigned char SHLogger::configFlags = DEFAULT_CONFIG_FLAG; + SHLogger::DateFormat SHLogger::dateFormat = SHLogger::DateFormat::DD_MM_YY; + std::string SHLogger::trivialPattern; + std::string SHLogger::verbosePattern; + + std::string SHLogger::fileName; + std::filesystem::path SHLogger::directoryPath; + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHLogger::SetConfig(const Config& config) noexcept + { + unsigned char flags = 0U; + + if (config.showTime) + flags |= 1U << 0; + + if (config.clockFormat == ClockFormat::_24HR) + flags |= 1U << 1; + + if (config.showDate) + flags |= 1U << 2; + + if (config.showFunctionFileName) + flags |= 1U << 3; + + if (config.showFunctionLineNumber) + flags |= 1U << 4; + + configFlags = flags; + dateFormat = config.dateFormat; + + fileName = config.fileName; + directoryPath = config.directoryPath; + + UpdatePatterns(); + } + + void SHLogger::SetShowTime(bool showTime) noexcept + { + constexpr char RAW = 1U << 0; + showTime ? configFlags |= RAW : configFlags &= ~(RAW); + UpdatePatterns(); + } + + void SHLogger::SetShowDate(bool showDate) noexcept + { + constexpr char RAW = 1U << 2; + showDate ? configFlags |= RAW : configFlags &= ~(RAW); + UpdatePatterns(); + } + + void SHLogger::SetShowFunctionFileName(bool showFunctionFileName) noexcept + { + constexpr char RAW = 1U << 3; + showFunctionFileName ? configFlags |= RAW : configFlags &= ~(RAW); + UpdatePatterns(); + } + + void SHLogger::SetShowFunctionLineNumber(bool showFunctionLineNumber) noexcept + { + constexpr char RAW = 1U << 4; + showFunctionLineNumber ? configFlags |= RAW : configFlags &= ~(RAW); + UpdatePatterns(); + } + + void SHLogger::SetClockFormat(ClockFormat newClockFormat) noexcept + { + constexpr char RAW = 1U << 1; + newClockFormat == ClockFormat::_24HR ? configFlags |= RAW : configFlags &= ~(RAW); + UpdatePatterns(); + } + + void SHLogger::SetDateFormat(DateFormat newDateFormat) noexcept + { + dateFormat = newDateFormat; + UpdatePatterns(); + } + + void SHLogger::SetFileName(const std::string& logFileName) noexcept + { + if (CheckInitialisation("Logger has already been initialised!")) + return; + + fileName = logFileName; + } + + void SHLogger::SetDirectoryPath(const std::filesystem::path& logDirectoryPath) noexcept + { + if (CheckInitialisation("Logger has already been initialised!")) + return; + + if (!is_directory(logDirectoryPath)) + { + spdlog::get(SHLOGGER_NAME)->info("Supplied path is not a directory!"); + return; + } + + directoryPath = logDirectoryPath; + } + + void SHLogger::SetFlushTime(int seconds) noexcept + { + spdlog::flush_every(std::chrono::seconds(seconds)); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHLogger::Initialise(const Config& config) + { + SetConfig(config); + + // Initialise default fileName if fileName was not set + if (fileName.empty()) + { + // Get current date and time + const auto NOW = std::time(nullptr); + std::tm localTime; + localtime_s(&localTime, &NOW); + + std::stringstream tmp; + tmp << "SHADE Log_" << std::put_time(&localTime, "%F %H.%M.%S") << ".txt"; + + fileName = tmp.str(); + } + + CreateConsole(); + + try + { + std::vector sinks; + + // Colour console + const auto& COLOUR_CONSOLE_SINK = sinks.emplace_back(std::make_shared()); + COLOUR_CONSOLE_SINK->set_pattern("%^" + trivialPattern + "%v%$"); + + // File + const std::string FULL_FILE_PATH = directoryPath.string() + fileName; + const auto& FILE_SINK = sinks.emplace_back(std::make_shared(FULL_FILE_PATH)); + FILE_SINK->set_pattern(trivialPattern + "%v"); + + // Create and register logger with spdlog + const auto LOGGER = std::make_shared(SHLOGGER_NAME, sinks.begin(), sinks.end()); + LOGGER->set_level(spdlog::level::trace); + LOGGER->flush_on(spdlog::level::trace); + register_logger(LOGGER); + + // Flush every 3 seconds + spdlog::flush_every(std::chrono::seconds(config.flushTime)); + + configFlags |= (1U << 7); + } + catch (const spdlog::spdlog_ex& e) + { + std::cout << "Log initialisation failed: " << e.what() << std::endl; + } + } + + void SHLogger::Shutdown() noexcept + { + spdlog::shutdown(); + } + + void SHLogger::UseTrivialPattern() noexcept + { + auto& sinks = spdlog::get(SHLOGGER_NAME)->sinks(); + sinks[0]->set_pattern("%^" + trivialPattern + "%v%$"); // Colour Console Sink + sinks[1]->set_pattern(trivialPattern + "%v"); // File Sink + } + + void SHLogger::UseVerbosePattern() noexcept + { + auto& sinks = spdlog::get(SHLOGGER_NAME)->sinks(); + sinks[0]->set_pattern("%^" + verbosePattern + "%v%$"); // Colour Console Sink + sinks[1]->set_pattern(verbosePattern + "%v"); // File Sink + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHLogger::CreateConsole() + { + bool result = false; + DestroyConsole(); + + if (AllocConsole()) + { + const HANDLE CONSOLE = GetStdHandle(STD_OUTPUT_HANDLE); + + // Set the screen buffer to be big enough to scroll some text + CONSOLE_SCREEN_BUFFER_INFO conInfo; + GetConsoleScreenBufferInfo(CONSOLE, &conInfo); + + if (conInfo.dwSize.Y < DEFAULT_CONSOLE_LEN) + { + conInfo.dwSize.Y = DEFAULT_CONSOLE_LEN; + } + + SetConsoleScreenBufferSize(CONSOLE, conInfo.dwSize); + + result = RedirectConsoleIO(); + } + + return result; + } + + bool SHLogger::RedirectConsoleIO() + { + bool result = true; + + FILE* fp; + + // Redirect STDIN if the console has an input handle + if (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) + { + if (freopen_s(&fp, "CONIN$", "r", stdin) != 0) + { + result = false; + } + else + { + setvbuf(stdin, nullptr, _IONBF, 0); + } + } + + // Redirect STDOUT if the console has an output handle + if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) + { + if (freopen_s(&fp, "CONOUT$", "w", stdout) != 0) + { + result = false; + } + else + { + setvbuf(stdout, nullptr, _IONBF, 0); + } + } + + // Redirect STDERR if the console has an error handle + if (GetStdHandle(STD_ERROR_HANDLE) != INVALID_HANDLE_VALUE) + { + if (freopen_s(&fp, "CONOUT$", "w", stderr) != 0) + { + result = false; + } + else + { + setvbuf(stderr, nullptr, _IONBF, 0); + } + } + + // Make C++ standard streams point to console as well. + std::ios::sync_with_stdio(true); + + // Clear the error state for each of the C++ standard streams. + std::wcin.clear(); + std::cin.clear(); + std::wcout.clear(); + std::cout.clear(); + std::wcerr.clear(); + std::cerr.clear(); + + return result; + } + + + bool SHLogger::DestroyConsole() + { + bool result = true; + FILE* fP; + + // Just to be safe, redirect standard IO to NUL before releasing. + + // Redirect STDIN to NUL + if (freopen_s(&fP, "NUL:", "r", stdin) != 0) + { + result = false; + } + else + { + setvbuf(stdin, nullptr, _IONBF, 0); + } + + + // Redirect STDOUT to NUL + if (freopen_s(&fP, "NUL:", "w", stdout) != 0) + { + result = false; + } + else + { + setvbuf(stdout, nullptr, _IONBF, 0); + } + + // Redirect STDERR to NUL + if (freopen_s(&fP, "NUL:", "w", stderr) != 0) + { + result = false; + } + else + { + setvbuf(stderr, nullptr, _IONBF, 0); + } + + // Detach console + if (result) + return FreeConsole(); + + return result; + } + + bool SHLogger::CheckInitialisation(const std::string_view& msg) + { + const bool INITIALISED = configFlags & (1U << 7); + if (INITIALISED) + { + spdlog::get(SHLOGGER_NAME)->warn(msg); + return true; + } + + return false; + } + + void SHLogger::UpdatePatterns() + { + const std::string DATE_TIME_PATTERN = BuildDateTimePattern(); + const std::string VERBOSE_PATTERN = BuildVerbosePattern(); + + trivialPattern = DATE_TIME_PATTERN; + verbosePattern = DATE_TIME_PATTERN + VERBOSE_PATTERN; + } + + std::string SHLogger::BuildDateTimePattern() + { + const bool SHOW_TIME = configFlags & (1U << 0); + const bool SHOW_DATE = configFlags & (1U << 2); + + std::string pattern; + if (SHOW_DATE || SHOW_TIME) + { + pattern.append("["); + { + if (SHOW_DATE) + { + pattern.append(GetDatePattern(dateFormat)); + } + + // Put a space in between date and time + if (SHOW_DATE && SHOW_TIME) + { + pattern.append(" "); + } + + if (SHOW_TIME) + { + const bool IS_24HR = configFlags & (1U << 1); + pattern.append(GetClockPattern(IS_24HR)); + } + } + pattern.append("] "); + } + + return pattern; + } + + std::string SHLogger::BuildVerbosePattern() + { + const bool SHOW_SRC_FILE = configFlags & (1U << 3); + const bool SHOW_SRC_LINE = configFlags & (1U << 4); + + std::string pattern { "[" }; + if (SHOW_SRC_FILE) + { + pattern.append("%s, "); + if (SHOW_SRC_LINE) + { + pattern.append("%#, "); + } + } + + pattern.append("%!] "); + return pattern; + } + +} // namespace SHADE + +std::string GetDatePattern(SHADE::SHLogger::DateFormat fmt) +{ + switch (fmt) + { + case SHADE::SHLogger::DateFormat::DD_MM_YY: return std::string { "%d-%m-%Y" }; + case SHADE::SHLogger::DateFormat::MM_DD_YY: return std::string { "%m-%d-%Y" }; + case SHADE::SHLogger::DateFormat::YY_MM_DD: return std::string { "%Y-%m-%d" }; + case SHADE::SHLogger::DateFormat::DD_Mth_YY: return std::string { "%d %b, %Y" }; + case SHADE::SHLogger::DateFormat::Mth_DD_YY: return std::string { "%b %d, %Y" }; + + default: return std::string { "%d-%m-%Y" }; + } +} + +std::string GetClockPattern(bool is24HR) +{ + return is24HR ? "%H:%M:%S" : "%I:%M:%S %p"; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Tools/SHLogger.h b/SHADE_Engine/src/Tools/SHLogger.h new file mode 100644 index 00000000..ac5f9308 --- /dev/null +++ b/SHADE_Engine/src/Tools/SHLogger.h @@ -0,0 +1,174 @@ +/**************************************************************************************** + * \file SHLogger.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for SHADE Engine's logger. + * + * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. +****************************************************************************************/ + +#pragma once + +#include +#include + +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE +#include + +/*-------------------------------------------------------------------------------------*/ +/* Macros */ +/*-------------------------------------------------------------------------------------*/ +#define SHLOGGER_NAME "SHLogger" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHLogger + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + enum class ClockFormat { _12HR, _24HR }; + + enum class DateFormat + { + DD_MM_YY // 25-12-2022 + , MM_DD_YY // 12-25-2022 + , YY_MM_DD // 2022-12-25 + , DD_Mth_YY // 25 Dec, 2022 + , Mth_DD_YY // Dec 25, 2022 + }; + + /** + * @brief Defines configuration parameters for the logger. + */ + struct Config + { + /*-------------------------------------------------------------------------------*/ + /* Data Members */ + /*-------------------------------------------------------------------------------*/ + bool showTime = true; + bool showDate = true; + bool showFunctionFileName = true; + bool showFunctionLineNumber = true; + + ClockFormat clockFormat = ClockFormat::_12HR; + DateFormat dateFormat = DateFormat::DD_MM_YY; + std::string fileName; + std::filesystem::path directoryPath; + + int flushTime = 1; + }; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] static const std::string& GetTrivialPattern () noexcept { return trivialPattern; } + [[nodiscard]] static const std::string& GetVerbosePattern () noexcept { return verbosePattern; } + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + static void SetTrivialPattern (const std::string& pattern) noexcept { trivialPattern = pattern; } + static void SetVerbosePattern (const std::string& pattern) noexcept { verbosePattern = pattern; } + + static void SetConfig (const Config& config) noexcept; + + static void SetShowTime (bool showTime) noexcept; + static void SetShowDate (bool showDate) noexcept; + static void SetShowFunctionFileName (bool showFunctionFileName) noexcept; + static void SetShowFunctionLineNumber (bool showFunctionLineNumber) noexcept; + + static void SetClockFormat (ClockFormat newClockFormat) noexcept; + static void SetDateFormat (DateFormat newDateFormat) noexcept; + + + + static void SetFileName (const std::string& logFileName) noexcept; + static void SetDirectoryPath (const std::filesystem::path& logDirectoryPath) noexcept; + + static void SetFlushTime (int seconds) noexcept; + static void SetFlushTime (size_t seconds) noexcept { spdlog::flush_every(std::chrono::seconds(seconds)); } + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief Creates a console and a file to log to. + * @param[in] config The configuration parameters for the logger. + */ + static void Initialise (const Config& config = Config{}); + static void Shutdown () noexcept; + + /** + * @brief The next message logged by the logger will be set to follow the trivial pattern. + */ + static void UseTrivialPattern () noexcept; + /** + * @brief The next message logged by the logger will be set to follow the verbose pattern. + */ + static void UseVerbosePattern () noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + static constexpr char DEFAULT_CONFIG_FLAG = 0b00011101; // 00011101 + static constexpr short DEFAULT_CONSOLE_LEN = 1024; + + static unsigned char configFlags; // Initialised 0 0 FuncLine# FuncFileName Date TimeFormat Time + static DateFormat dateFormat; + + static std::string trivialPattern; + static std::string verbosePattern; + + static std::string fileName; + static std::filesystem::path directoryPath; // For file logging + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + static bool CreateConsole (); + static bool RedirectConsoleIO (); + static bool DestroyConsole (); + + static bool CheckInitialisation (const std::string_view& msg); + static void UpdatePatterns (); + static std::string BuildDateTimePattern(); + static std::string BuildVerbosePattern (); + }; + +} // namespace SHADE + +/*-------------------------------------------------------------------------------------*/ +/* Macros */ +/*-------------------------------------------------------------------------------------*/ + +#ifdef _DEBUG + #define SHLOG_TRACE(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_TRACE(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); + #define SHLOGV_TRACE(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_TRACE(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); +#endif + +#define SHLOG_INFO(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); +#define SHLOGV_INFO(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); + +#define SHLOG_WARNING(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_WARN(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); +#define SHLOGV_WARNING(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_WARN(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); + +#define SHLOG_ERROR(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_ERROR(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); +#define SHLOGV_ERROR(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_ERROR(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); + +#define SHLOG_CRITICAL(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_CRITICAL(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); +#define SHLOGV_CRITICAL(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_CRITICAL(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__); + +// Misc Logging Macros +#define SHLOG_FLOOR() SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), "--------------------------------"); \ No newline at end of file