From a92e55ee0112013895f9ca5985fc2ca0449f6a51 Mon Sep 17 00:00:00 2001 From: Joeyrp Date: Wed, 1 Sep 2021 20:46:45 -0400 Subject: [PATCH] Adds binary file buffer and the basics of the Window class --- CMakeLists.txt | 6 ++ LunariumConfig.h.in | 7 +- src/core/core.cpp | 32 +++++- src/core/core.h | 7 ++ src/core/state.cpp | 27 ++++- src/core/state.h | 8 ++ src/graphics/window.cpp | 183 +++++++++++++++++++++++++++++++++ src/graphics/window.h | 54 ++++++++++ src/utils/BinaryFileBuffer.cpp | 108 +++++++++++++++++++ src/utils/BinaryFileBuffer.h | 44 ++++++++ src/utils/helpers.cpp | 126 ++++++++++++++++++++++- src/utils/helpers.h | 36 ++++++- test_data/test_state.xml | 2 +- 13 files changed, 624 insertions(+), 16 deletions(-) create mode 100644 src/graphics/window.cpp create mode 100644 src/graphics/window.h create mode 100644 src/utils/BinaryFileBuffer.cpp create mode 100644 src/utils/BinaryFileBuffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 70536b0..3b78d26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,10 @@ project(Lunarium VERSION 0.1.0) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) +# specify the opengl version +set(OpenGL_MAJOR_VERSION 4) +set(OpenGL_MINOR_VERSION 5) + configure_file(LunariumConfig.h.in LunariumConfig.h) # Source Files @@ -20,6 +24,8 @@ set(LUNARIUM_SRC "src/utils/helpers.cpp" "src/utils/OpRes.cpp" "src/utils/Args.cpp" +"src/utils/BinaryFileBuffer.cpp" +"src/graphics/window.cpp" ) # add the executable diff --git a/LunariumConfig.h.in b/LunariumConfig.h.in index acb787e..2bb0a80 100644 --- a/LunariumConfig.h.in +++ b/LunariumConfig.h.in @@ -1,4 +1,7 @@ -// the configured options and settings for GLFW_Testing +// the configured options and settings for Lunarium #define Lunarium_VERSION_MAJOR @Lunarium_VERSION_MAJOR@ #define Lunarium_VERSION_MINOR @Lunarium_VERSION_MINOR@ -#define Lunarium_VERSION_PATCH @Lunarium_VERSION_PATCH@ \ No newline at end of file +#define Lunarium_VERSION_PATCH @Lunarium_VERSION_PATCH@ + +#define OPENGL_MAJOR_VERSION @OpenGL_MAJOR_VERSION@ +#define OPENGL_MINOR_VERSION @OpenGL_MINOR_VERSION@ \ No newline at end of file diff --git a/src/core/core.cpp b/src/core/core.cpp index 8ff5ff6..580fee9 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -13,7 +13,7 @@ namespace lunarium { Core* Core::mpInstance = nullptr; Core::Core() - : mbIsInit(false) + : mbIsInit(false), mpArgs(nullptr) { } @@ -35,13 +35,31 @@ namespace lunarium // Shutdown subsystems + delete mpInstance->mpArgs; + mpInstance->mpArgs = nullptr; + delete mpInstance; mpInstance = nullptr; } void Core::Initialize(int argc, char** argv, std::vector& listeners) { + // Setup the log system and add any listeners mpLog = Logger::GetInstance(); + + mMasterLogFile.open("Element2D_Master.log", std::ios_base::app); + mMasterLogFile << "\n\n"; + + + mErrorLogFile.open("Element2D_Errors.log", std::ios_base::app); + mErrorLogFile << "\n\n"; + + if (mMasterLogFile.is_open()) + mpLog->AddListener(new FileListener(mMasterLogFile)); + + + if (mErrorLogFile.is_open()) + mpLog->AddListener(new FileListener(mErrorLogFile, LogLevel::ERROR | LogLevel::FATAL_ERROR)); for (unsigned i = 0; i < listeners.size(); i++) { @@ -49,6 +67,18 @@ namespace lunarium } mpLog->Log(LogCategory::CORE, LogLevel::INFO, "Running Lunarium version %s", Version::GetVersion().ToString().c_str()); + + // Attempt to load the engine state file. This file should be placed in the same directory as the lunarium program. + mpLog->Log(LogCategory::CORE, LogLevel::INFO, "Attempting to load state file: lunarium_state.xml"); + if (Failed(State::CreateFromFile("lunarium_state.xml", mState))) + { + mpLog->Log(LogCategory::CORE, LogLevel::WARNING, "Unable to load state file: lunarium_state.xml. Loading default state."); + mState = State::CreateDefault(); + } + + // Parse command line args -- None right now + std::vector sd; + mpArgs = new Args(argc, argv, '-', sd); } bool Core::IsInit() const diff --git a/src/core/core.h b/src/core/core.h index 4946006..57a3bcd 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -26,12 +26,19 @@ namespace lunarium bool IsInit() const; const State& GetState() const; + void ApplyState(State newState); + private: // DATA static Core* mpInstance; bool mbIsInit; State mState; + Args* mpArgs; Logger* mpLog; + // Log Files + std::ofstream mMasterLogFile; + std::ofstream mErrorLogFile; + private: // HIDDEN METHODS Core(); diff --git a/src/core/state.cpp b/src/core/state.cpp index 2045f21..633bccf 100644 --- a/src/core/state.cpp +++ b/src/core/state.cpp @@ -18,6 +18,7 @@ namespace lunarium s.DataDirectory = ""; s.Display.FullScreenResolution.Width = 0; s.Display.FullScreenResolution.Height = 0; + s.Display.RenderFramework = Renderer::OPENGL; s.Display.IsFullScreen = false; s.Display.VSyncEnabled = false; s.Display.WindowedSize.Width = 0; @@ -34,9 +35,10 @@ namespace lunarium State s; s.DataDirectory = "data/"; - Sizei size = GetScreenResolution(); + Sizei size = System::GetScreenResolution(); s.Display.FullScreenResolution.Width = size.Width; s.Display.FullScreenResolution.Height = size.Height; + s.Display.RenderFramework = Renderer::OPENGL; s.Display.IsFullScreen = false; s.Display.VSyncEnabled = true; s.Display.WindowedSize.Width = 800; @@ -74,9 +76,10 @@ namespace lunarium pugi::xml_node display = root.child("Display"); if (pugi::node_null == display.type()) { - Sizei size = GetScreenResolution(); + Sizei size = System::GetScreenResolution(); state.Display.FullScreenResolution.Width = size.Width; state.Display.FullScreenResolution.Height = size.Height; + state.Display.RenderFramework = Renderer::OPENGL; state.Display.IsFullScreen = false; state.Display.VSyncEnabled = true; state.Display.WindowedSize.Width = 800; @@ -88,6 +91,21 @@ namespace lunarium { state.Display.FullScreenResolution.Width = display.child("FullScreenResolution").attribute("Width").as_int(); state.Display.FullScreenResolution.Height = display.child("FullScreenResolution").attribute("Height").as_int(); + + std::string framework = display.attribute("RenderFramework").as_string(); + if (String::StringToLower(framework) == "opengl") + { + state.Display.RenderFramework = Renderer::OPENGL; + } + else if (String::StringToLower(framework) == "vulkan") + { + state.Display.RenderFramework = Renderer::VULKAN; + } + else + { + state.Display.RenderFramework = Renderer::UNKNOWN; + } + state.Display.IsFullScreen = display.attribute("IsFullScreen").as_bool(); state.Display.VSyncEnabled = display.attribute("VSyncEnabled").as_bool(); state.Display.WindowedSize.Width = display.child("WindowedSize").attribute("Width").as_int(); @@ -124,7 +142,10 @@ namespace lunarium pugi::xml_node display = doc.child("State").append_child("Display"); display.append_attribute("IsFullScreen").set_value(Display.IsFullScreen); display.append_attribute("VSyncEnabled").set_value(Display.VSyncEnabled); - + + char* names[] = { "opengl", "vulkan", "unknown" }; + display.append_attribute("RenderFramework").set_value(names[Display.RenderFramework]); + pugi::xml_node fsr = display.append_child("FullScreenResolution"); fsr.append_attribute("Width").set_value(Display.FullScreenResolution.Width); fsr.append_attribute("Height").set_value(Display.FullScreenResolution.Height); diff --git a/src/core/state.h b/src/core/state.h index e3cb39b..a61f44c 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -14,6 +14,13 @@ namespace lunarium { + enum Renderer + { + OPENGL, + VULKAN, + UNKNOWN + }; + struct State { std::string DataDirectory; @@ -38,6 +45,7 @@ namespace lunarium int Height; } FullScreenResolution; + Renderer RenderFramework; bool IsFullScreen; bool VSyncEnabled; } Display; diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp new file mode 100644 index 0000000..2515ebd --- /dev/null +++ b/src/graphics/window.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** +* File - window.h +* Author - Joey Pollack +* Date - 2021/09/01 (y/m/d) +* Mod Date - 2021/09/01 (y/m/d) +* Description - Manages the window system using GLFW. This is where GLFW +* is initialized. I think this file can completely hide GLFW +* but I'm not yet sure... +******************************************************************************/ + +#include "window.h" +#include +#include +#include +#include + +namespace lunarium +{ + bool Window::mbIsInit = false; + Window::Window() + { + + } + + OpRes Window::Initialize(const State& state) + { + if (mbIsInit) + { + return OpRes::Fail("A window is already initialized. Multiple windows is not yet supported"); + } + + if (state.Display.RenderFramework == Renderer::VULKAN) + { + return OpRes::Fail("Render Framework VULKAN is not yet implemented"); + } + + if (state.Display.RenderFramework == Renderer::OPENGL) + { + int width, height; + + if( !glfwInit() ) + { + char buffer[1024]; + glfwGetError((char**)&buffer); + std::ostringstream oss; + oss << "Failed to initialize GLFW: " << buffer; + return OpRes::Fail(oss.str().c_str()); + } + + glfwWindowHint(GLFW_DEPTH_BITS, 16); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_MAJOR_VERSION); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_MINOR_VERSION); + + Logger::GetInstance()->Log(LogCategory::GRAPHICS, LogLevel::INFO, + "Creating OpenGL Context version %d, %d and glsl %s", + OPENGL_MAJOR_VERSION, OPENGL_MINOR_VERSION, System::GetGLSLVersionString().c_str()); + + mpWindow = glfwCreateWindow( state.Display.WindowedSize.Width, state.Display.WindowedSize.Height, "Lunarium", NULL, NULL ); + if (!mpWindow) + { + glfwTerminate(); + char buffer[1024]; + glfwGetError((char**)&buffer); + std::ostringstream oss; + oss << "Failed to initialize GLFWFailed to open GLFW window: " << buffer; + return OpRes::Fail(oss.str().c_str()); + } + + glfwSetWindowPos(mpWindow, state.Display.WindowStartPosition.X, state.Display.WindowStartPosition.Y); + + glfwMakeContextCurrent(mpWindow); + + if (state.Display.VSyncEnabled) + { + glfwSwapInterval(1); // Enable vsync + } + + // Use glad2 to load extensions + int version = gladLoadGL(glfwGetProcAddress); + Logger::GetInstance()->Log(LogCategory::GRAPHICS, LogLevel::INFO, + "Glad2 Loaded version: %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)); + } + else + { + return OpRes::Fail("No Render Framework selected"); + } + + glfwSetWindowUserPointer(mpWindow, this); + mbIsInit = true; + return OpRes::OK(); + } + + bool Window::IsInit() const + { + return mbIsInit; + } + + GLFWwindow* Window::GetWindow() + { + return mpWindow; + } + + void Window::Resize(int width, int height) + { + glfwSetWindowSize(mpWindow, width, height); + } + + + // If fullscreen is true but we're already in fullscreen mode this function will change the + // resolution. If fullscreen is false but we're not fullscreen this function will change + // the window position and size. + void Window::ChangeDisplayMode(bool fullscreen, int xPos, int yPos, int width, int height) + { + // TODO: Allow the user to select which monitor to use + // https://www.glfw.org/docs/latest/monitor_guide.html + // For now just use the primary monitor + + GLFWmonitor* pMonitor = glfwGetWindowMonitor(mpWindow); + + if (fullscreen) + { + if (pMonitor) + { + // Requsting fullscreen but we're already fullscreen so + // just set the size + glfwSetWindowSize(mpWindow, width, height); + return; + } + else + { + // Otherwise we need to switch to fullscreen mode + // TODO: Allow the user to select the refresh rate + glfwSetWindowMonitor(mpWindow, glfwGetPrimaryMonitor(), 0, 0, width, height, 60); + } + } + else + { + if (pMonitor) + { + // Go to windowed mode + glfwSetWindowMonitor(mpWindow, nullptr, xPos, yPos, width, height, 60); + } + else + { + // Already in windowed mode so just change the size and position + glfwSetWindowSize(mpWindow, width, height); + glfwSetWindowPos(mpWindow, xPos, yPos); + } + } + } + + void Window::GetFramebufferSize(int* width, int* height) const + { + glfwGetFramebufferSize(mpWindow, width, height); + } + + + bool Window::ShouldWindowClose() const + { + return glfwWindowShouldClose(mpWindow); + } + + void Window::PollEvents() + { + glfwPollEvents(); + } + + void Window::SwapBuffers() + { + glfwSwapBuffers(mpWindow); + } + + + void Window::Shutdown() + { + glfwDestroyWindow(mpWindow); + glfwTerminate(); + mbIsInit = false; + } + +} \ No newline at end of file diff --git a/src/graphics/window.h b/src/graphics/window.h new file mode 100644 index 0000000..44c1d29 --- /dev/null +++ b/src/graphics/window.h @@ -0,0 +1,54 @@ +/****************************************************************************** +* File - window.h +* Author - Joey Pollack +* Date - 2021/09/01 (y/m/d) +* Mod Date - 2021/09/01 (y/m/d) +* Description - Manages the window system using GLFW. This is where GLFW +* is initialized. I think this file can completely hide GLFW +* but I'm not yet sure... +******************************************************************************/ + +#ifndef WINDOW_H_ +#define WINDOW_H_ + +#include +#include +#include +#include + +namespace lunarium +{ + class Window + { + public: + Window(); + + OpRes Initialize(const State& state); + bool IsInit() const; + + GLFWwindow* GetWindow(); + + + void Resize(int width, int height); + + // TODO: See https://www.glfw.org/docs/latest/window_guide.html#window_full_screen + void ChangeDisplayMode(bool fullscreen, int xPos, int yPos, int width, int height); + + void GetFramebufferSize(int* width, int* height) const; + + bool ShouldWindowClose() const; + static void PollEvents(); + void SwapBuffers(); + + void Shutdown(); + + private: + + // There can only be 1 window for now + static bool mbIsInit; + GLFWwindow* mpWindow; + + }; +} + +#endif // WINDOW_H_ \ No newline at end of file diff --git a/src/utils/BinaryFileBuffer.cpp b/src/utils/BinaryFileBuffer.cpp new file mode 100644 index 0000000..4001fdd --- /dev/null +++ b/src/utils/BinaryFileBuffer.cpp @@ -0,0 +1,108 @@ +/****************************************************************************** +* File - BinaryFileBuffer.cpp +* Author - Joey Pollack +* Date - 2020/01/24 (y/m/d) +* Mod Date - 2020/01/24 (y/m/d) +* Description - Reads an entire binary file into memory and allows for +* extracting the data in chunks. Much faster than reading +* large files chunk by chunk. +******************************************************************************/ + +#include "BinaryFileBuffer.h" +#include + +namespace lunarium +{ + BinaryFileBuffer::BinaryFileBuffer() + : mbIsLoaded(false), mpData(nullptr), mFileSize(0), mReadPos(0), mFileName("") + { + } + + BinaryFileBuffer::~BinaryFileBuffer() + { + Unload(); + } + + bool BinaryFileBuffer::LoadFile(const char * filename) + { + if (mbIsLoaded) + { + return false; + } + + std::ifstream ifs(filename, std::ios_base::binary); + if (!ifs.is_open()) + { + return false; + } + + int start = ifs.tellg(); + ifs.seekg(0, std::ios_base::end); + int end = ifs.tellg(); + ifs.seekg(0, std::ios_base::beg); + + mFileSize = end - start; + mpData = new unsigned char[mFileSize]; + + ifs.read((char*)mpData, mFileSize); + + ifs.close(); + ifs.clear(); + + mFileName = filename; + mbIsLoaded = true; + return true; + } + + void BinaryFileBuffer::Unload() + { + if (!mbIsLoaded) + return; + + delete[] mpData; + mpData = nullptr; + + mFileSize = 0; + mFileName = ""; + mReadPos = 0; + mbIsLoaded = false; + } + + bool BinaryFileBuffer::IsLoaded() const + { + return mbIsLoaded; + } + + const std::string& BinaryFileBuffer::LoadedFileName() const + { + return mFileName; + } + + int BinaryFileBuffer::GetFileSize() const + { + return mFileSize; + } + + bool BinaryFileBuffer::Read(char * buffer, int numBytes) + { + if (!mbIsLoaded || mReadPos >= mFileSize) + return false; + + memcpy_s(buffer, numBytes, &mpData[mReadPos], numBytes); + mReadPos += numBytes; + + return true; + } + + void BinaryFileBuffer::SeekTo(int pos) + { + mReadPos = pos; + + if (mReadPos < 0) + mReadPos = 0; + + if (mReadPos >= mFileSize) + mReadPos = mFileSize - 1; + } + +} \ No newline at end of file diff --git a/src/utils/BinaryFileBuffer.h b/src/utils/BinaryFileBuffer.h new file mode 100644 index 0000000..499049b --- /dev/null +++ b/src/utils/BinaryFileBuffer.h @@ -0,0 +1,44 @@ +/****************************************************************************** +* File - BinaryFileBuffer.h +* Author - Joey Pollack +* Date - 2020/01/24 (y/m/d) +* Mod Date - 2020/01/24 (y/m/d) +* Description - Reads an entire binary file into memory and allows for +* extracting the data in chunks. Much faster than reading +* large files chunk by chunk. +******************************************************************************/ + +#ifndef BINARY_FILE_BUFFER_H_ +#define BINARY_FILE_BUFFER_H_ + +#include + +namespace lunarium +{ + class BinaryFileBuffer + { + public: + BinaryFileBuffer(); + ~BinaryFileBuffer(); + + bool LoadFile(const char* filename); + void Unload(); + bool IsLoaded() const; + const std::string& LoadedFileName() const; + int GetFileSize() const; + + bool Read(char* buffer, int numBytes); + void SeekTo(int pos); + + private: + + bool mbIsLoaded; + std::string mFileName; + int mFileSize; + unsigned char* mpData; + int mReadPos; + + }; +} + +#endif // BINARY_FILE_BUFFER_H_ \ No newline at end of file diff --git a/src/utils/helpers.cpp b/src/utils/helpers.cpp index 6162098..446a319 100644 --- a/src/utils/helpers.cpp +++ b/src/utils/helpers.cpp @@ -7,6 +7,7 @@ ******************************************************************************/ #include "helpers.h" +#include #ifdef WIN32 #include @@ -16,7 +17,7 @@ namespace lunarium { - Sizei GetScreenResolution() + Sizei System::GetScreenResolution() { #ifdef WIN32 return Sizei { GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN) }; @@ -27,25 +28,142 @@ namespace lunarium #endif // WIN32 } + std::string System::GetGLSLVersionString() + { + std::string glsl_version = "#version "; + glsl_version += OPENGL_MAJOR_VERSION; + glsl_version += OPENGL_MINOR_VERSION; + glsl_version += "0"; + return glsl_version; + } + + std::vector String::Split(std::string str, char delim, int maxSplits) + { + std::vector splits; + + int startPos = 0; + for (int i = 0; i < (signed)str.length(); i++) + { + if (str[i] == delim) + { + if (startPos == i) + continue; + + std::string s = str.substr(startPos, i - startPos); + splits.push_back(s); + startPos = i + 1; + + if (maxSplits > 0 && (signed)splits.size() >= (maxSplits - 1)) + { + break; + } + } + } + + std::string s = str.substr(startPos); + splits.push_back(s); + return splits; + } + + std::string String::Trim(std::string str, std::string delims) + { + str = TrimStart(str, delims); + str = TrimEnd(str, delims); + return str; + } + + + std::string String::TrimStart(std::string str, std::string delims) + { + bool isDelim = true; + while (isDelim && str.length() > 0) + { + isDelim = false; + for (int i = 0; i < (signed)delims.length(); i++) + { + if (str[0] == delims[i]) + { + isDelim = true; + break; + } + } + + if (isDelim) + str.erase(str.begin()); + } + + return str; + } + + + std::string String::TrimEnd(std::string str, std::string delims) + { + bool isDelim = true; + while (isDelim && str.length() > 0) + { + isDelim = false; + for (int i = 0; i < (signed)delims.length(); i++) + { + if (*(str.rbegin()) == delims[i]) + { + isDelim = true; + break; + } + } + + if (isDelim) + str.erase((str.rbegin() + 1).base()); + } + + return str; + } + //template - std::string AsString(int value) + std::string String::AsString(int value) { std::string str = ""; str += value; return str; } - std::string AsString(bool value) + std::string String::AsString(bool value) { std::string str = ""; str += value; return str; } - std::string AsString(float value) + std::string String::AsString(float value) { std::string str = ""; str += value; return str; } + + + std::string String::StringToUpper(std::string str) + { + for (int i = 0; i < str.size(); i++) + { + if (str[i] >= 97 && str[i] <= 122) + { + str[i] -= 32; + } + } + + return str; + } + + std::string String::StringToLower(std::string str) + { + for (int i = 0; i < str.size(); i++) + { + if (str[i] >= 65 && str[i] <= 90) + { + str[i] += 32; + } + } + + return str; + } } \ No newline at end of file diff --git a/src/utils/helpers.h b/src/utils/helpers.h index 11302cf..b95fe40 100644 --- a/src/utils/helpers.h +++ b/src/utils/helpers.h @@ -11,15 +11,41 @@ #include "types.h" #include +#include namespace lunarium { - Sizei GetScreenResolution(); + class System + { + public: + static Sizei GetScreenResolution(); + static std::string GetGLSLVersionString(); + }; - //template - std::string AsString(int value); - std::string AsString(bool value); - std::string AsString(float value); + class String + { + public: + + // Splits the string based on the given delimiter, + // maxSplit = -1 for unlimited number of splits + static std::vector Split(std::string str, char delim = ' ', int maxSplits = -1); + + // Trim given delimiters from start and end of string + static std::string Trim(std::string str, std::string delims = " \r\n\t"); + + // Trim given delimiters from start of string + static std::string TrimStart(std::string str, std::string delims = " \r\n\t"); + + // Trim given delimiters from end of string + static std::string TrimEnd(std::string str, std::string delims); + + static std::string AsString(int value); + static std::string AsString(bool value); + static std::string AsString(float value); + + static std::string StringToUpper(std::string str); + static std::string StringToLower(std::string str); + }; } #endif // HELPERS_H_ \ No newline at end of file diff --git a/test_data/test_state.xml b/test_data/test_state.xml index 55f5361..6a8ecf4 100644 --- a/test_data/test_state.xml +++ b/test_data/test_state.xml @@ -1,6 +1,6 @@ data/ - +