diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index bd7f9234..c9b8f0cd 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -101,7 +101,10 @@ add_library(bald_engine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/core/platform/opengl/textures/opengl_texture.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/core/utils/file_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/core/utils/image.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/core/utils/split_string.cpp ) + ${CMAKE_CURRENT_SOURCE_DIR}/src/core/utils/split_string.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/core/error/expected.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/core/error/unexpected.h + ) if (APPLE_BUILD) target_link_libraries(bald_engine @@ -164,6 +167,8 @@ target_link_libraries(runUnitTests bald_engine) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/test_file_manager.txt test_file_manager.txt COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/shaders/basic.vert res/shaders/basic.vert COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/shaders/basic.frag res/shaders/basic.frag COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/shaders/default.vert res/shaders/default.vert COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/shaders/default.frag res/shaders/default.frag COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/textures/fabric.jpg res/textures/fabric.jpg COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/textures/lena.jpg res/textures/lena.jpg COPYONLY) diff --git a/engine/res/shaders/default.frag b/engine/res/shaders/default.frag new file mode 100644 index 00000000..49400bc9 --- /dev/null +++ b/engine/res/shaders/default.frag @@ -0,0 +1,5 @@ +#version 330 + +void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/engine/res/shaders/default.vert b/engine/res/shaders/default.vert new file mode 100644 index 00000000..f405fbcd --- /dev/null +++ b/engine/res/shaders/default.vert @@ -0,0 +1,7 @@ +#version 330 + +layout (location = 0) in vec3 in_Position; + +void main() { + gl_Position = vec4(in_Position, 1.0); +} diff --git a/engine/src/core/error/expected.h b/engine/src/core/error/expected.h new file mode 100644 index 00000000..e84cae94 --- /dev/null +++ b/engine/src/core/error/expected.h @@ -0,0 +1,129 @@ +// +// Created by grzegorz on 18.09.19. +// + +#pragma once + +#include +#include "unexpected.h" +#include "bald_assert.h" + + +namespace Bald { + template + class expected { + public: + constexpr expected() { new(&m_Valid) E(); } + + constexpr expected(const E& rhs) { new(&m_Valid) E(rhs); } + + constexpr expected(const unexpected& rhs) : + _isOk(false) { new(&m_Invalid) U(rhs.value); } + + constexpr expected(E&& rhs) { new(&m_Valid) E(std::move(rhs)); } + + constexpr expected(unexpected&& rhs) : + _isOk(false) { new(&m_Invalid) U(std::move(rhs.m_Value)); } + + constexpr expected(const expected& rhs) : + _isOk(rhs._isOk) { + if (_isOk) new(&m_Valid) E(rhs.m_Valid); + else new(&m_Invalid) U(rhs.m_Invalid); + } + + constexpr expected(expected&& rhs) noexcept : + _isOk(rhs._isOk) { + if (_isOk) new(&m_Valid) E(std::move(rhs.m_Valid)); + else new(&m_Invalid) U(std::move(rhs.m_Invalid)); + } + + constexpr expected& operator=(const expected& rhs) { + if(this == &rhs) return *this; + dtor(); + _isOk = rhs._isOk; + if (_isOk) new(&m_Valid) E(rhs.m_Valid); + else new(&m_Invalid) U(rhs.m_Invalid); + return *this; + } + + constexpr expected& operator=(expected&& rhs) noexcept { + if(this == &rhs) return *this; + dtor(); + _isOk = rhs._isOk; + if (_isOk) new(&m_Valid) E(std::move(rhs.m_Valid)); + else new(&m_Invalid) U(std::move(rhs.m_Invalid)); + return *this; + } + + ~expected() { + dtor(); + } + + [[nodiscard]] constexpr bool isValid() const noexcept { +#ifdef DEBUG + m_WasChecked = true; +#endif + return _isOk; + } + + constexpr operator bool() const noexcept { +#ifdef DEBUG + m_WasChecked = true; +#endif + return _isOk; + } + + [[nodiscard]] constexpr U& error() const& { + BALD_ASSERT(m_WasChecked, "expected", "attempt to access value without calling isValid method", m_WasChecked); + BALD_ASSERT(!_isOk, "expected", "attempt to access invalid value after success", _isOk); + return m_Invalid; + } + + [[nodiscard]] U& error()& { + BALD_ASSERT(m_WasChecked, "expected", "attempt to access value without calling isValid method", m_WasChecked); + BALD_ASSERT(!_isOk, "expected", "attempt to access invalid value after success", _isOk); + return m_Invalid; + } + + [[nodiscard]] U&& error()&& { + BALD_ASSERT(m_WasChecked, "expected", "attempt to access value without calling isValid method", m_WasChecked); + BALD_ASSERT(!_isOk, "expected", "attempt to access invalid value after success", _isOk); + return std::move(m_Invalid); + } + + [[nodiscard]] constexpr E& value() const& { + BALD_ASSERT(m_WasChecked, "expected", "attempt to access value without calling isValid method", m_WasChecked); + BALD_ASSERT(_isOk, "expected", "attempt to access valid value after failure", _isOk); + return m_Valid; + } + + [[nodiscard]] E& value()& { + BALD_ASSERT(m_WasChecked, "expected", "attempt to access value without calling isValid method", m_WasChecked); + BALD_ASSERT(_isOk, "expected", "attempt to access valid value after failure", _isOk); + return m_Valid; + } + + [[nodiscard]] E&& value()&& { + BALD_ASSERT(m_WasChecked, "expected", "attempt to access value without calling isValid method", m_WasChecked); + BALD_ASSERT(_isOk, "expected", "attempt to access valid value after failure", _isOk); + return std::move(m_Valid); + } + + private: + void dtor() const noexcept { + if (_isOk) m_Valid.~E(); + else m_Invalid.~U(); + } + + private: + union { + E m_Valid; + U m_Invalid; + }; +#ifdef DEBUG + mutable bool m_WasChecked = false; +#endif + bool _isOk = true; + }; +} + diff --git a/engine/src/core/error/unexpected.h b/engine/src/core/error/unexpected.h new file mode 100644 index 00000000..ca21fe7f --- /dev/null +++ b/engine/src/core/error/unexpected.h @@ -0,0 +1,17 @@ +// +// Created by grzegorz on 18.09.19. +// +#pragma once + +namespace Bald { + template + struct unexpected { + constexpr explicit unexpected(const T& val): m_Value(val) { } + constexpr operator T() const noexcept { return m_Value; } + T m_Value; + }; +} + + + + diff --git a/engine/src/core/platform/opengl/shaders/opengl_shader.cpp b/engine/src/core/platform/opengl/shaders/opengl_shader.cpp index 47eff2e2..eeb3eb72 100644 --- a/engine/src/core/platform/opengl/shaders/opengl_shader.cpp +++ b/engine/src/core/platform/opengl/shaders/opengl_shader.cpp @@ -11,7 +11,8 @@ namespace Bald::Platform::Graphics { OpenGLShader::OpenGLShader(const char* vertexPath, const char* fragmentPath) - : m_VertexPath(vertexPath), m_FragmentPath(fragmentPath), m_ShaderID(CreateShader()) {} + : + m_VertexPath(vertexPath), m_FragmentPath(fragmentPath), m_ShaderID(CreateShader()) { } OpenGLShader::~OpenGLShader() { glDeleteProgram(m_ShaderID); @@ -66,7 +67,7 @@ namespace Bald::Platform::Graphics { } void OpenGLShader::SetUniform2i(const char* uniformName, int v0, int v1) const noexcept { - glUniform2i(GetUniformLocation(uniformName), v0,v1); + glUniform2i(GetUniformLocation(uniformName), v0, v1); } void OpenGLShader::SetUniform2i(const char* uniformName, const glm::tvec2& vec) const noexcept { @@ -95,19 +96,28 @@ namespace Bald::Platform::Graphics { unsigned OpenGLShader::CreateShader() const noexcept { int success = 0; - + using namespace Utils; unsigned int vertexShader; vertexShader = glCreateShader(GL_VERTEX_SHADER); - std::string vertexShaderSource = Utils::FileManager::ReadFile(m_VertexPath, - Utils::FileManager::Size::SMALL_FILE); + auto vertex_data = FileManager::ReadFile(m_VertexPath); + if (!vertex_data) { + CORE_LOG_WARN("Could't open shader: " + std::string(m_VertexPath)); + CORE_LOG_WARN("Compiling default shader instead"); + vertex_data = FileManager::ReadFile("../engine/res/shaders/default.vert"); + if(!vertex_data) { + CORE_LOG_ERROR("Could't open default shader"); + return 0; + } + } + const std::string& vertexShaderSource = vertex_data.value(); const char* vertexData = vertexShaderSource.c_str(); glShaderSource(vertexShader, 1, &vertexData, nullptr); glCompileShader(vertexShader); glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); - if(success == GL_FALSE) { + if (success == GL_FALSE) { int length = 0; glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &length); @@ -124,16 +134,26 @@ namespace Bald::Platform::Graphics { unsigned int fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + auto fragment_data = FileManager::ReadFile(m_FragmentPath); + + if (!fragment_data) { + CORE_LOG_WARN("Could't open shader: " + std::string(m_FragmentPath)); + CORE_LOG_WARN("Compiling default shader instead"); + fragment_data = FileManager::ReadFile("../engine/res/default.frag"); + if(!fragment_data) { + CORE_LOG_ERROR("Could't open default shader"); + return 0; + } + } - std::string fragmentShaderSource = Utils::FileManager::ReadFile(m_FragmentPath, - Utils::FileManager::Size::SMALL_FILE); + const std::string& fragmentShaderSource = fragment_data.value(); const char* fragmentData = fragmentShaderSource.c_str(); glShaderSource(fragmentShader, 1, &fragmentData, nullptr); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); - if(success == GL_FALSE) { + if (success == GL_FALSE) { int length = 0; glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &length); @@ -155,7 +175,7 @@ namespace Bald::Platform::Graphics { glLinkProgram(id); glGetProgramiv(id, GL_LINK_STATUS, &success); - if(success == GL_FALSE) { + if (success == GL_FALSE) { int length = 0; glGetProgramiv(id, GL_INFO_LOG_LENGTH, &length); @@ -184,7 +204,7 @@ namespace Bald::Platform::Graphics { int OpenGLShader::GetUniformLocation(const char* uniformName) const noexcept { auto iter = m_UniformLocationCache.find(uniformName); - if(iter != m_UniformLocationCache.end()) { + if (iter != m_UniformLocationCache.end()) { return iter->second; } diff --git a/engine/src/core/utils/file_manager.cpp b/engine/src/core/utils/file_manager.cpp index ad70da22..bbc16c3d 100644 --- a/engine/src/core/utils/file_manager.cpp +++ b/engine/src/core/utils/file_manager.cpp @@ -15,62 +15,56 @@ namespace Bald::Utils { - std::string FileManager::ReadFile(const char* filePath, Size size) { + expected FileManager::ReadFile(const char* filePath, Size size) { if (size == Size::SMALL_FILE) return ReadSmallFile(filePath); return ReadBigFile(filePath); } - std::string FileManager::ReadSmallFile(const char* filePath) { -#ifdef WINDOWS + expected FileManager::ReadSmallFile(const char* filePath) { +#if defined(WINDOWS) || defined(APPLE) FILE* file; - fopen_s(&file, filePath, "r"); + fopen_s(&file, filePath, "rb"); #else - FILE* file = fopen(filePath, "r"); + FILE* file = fopen(filePath, "rb"); #endif if (!file) { CORE_LOG_WARN("[FileManager] Couldn't open the file at path: " + static_cast(filePath)); - return "[FileManager] Couldn't open the file at path: " + static_cast(filePath); + return unexpected(FileManager::Error::CantOpenFile); } fseek(file, 0, SEEK_END); auto stringSize = static_cast(ftell(file)); fseek(file, 0, SEEK_SET); - - char* buffer; + std::string result; try { - buffer = new char[stringSize + 1]; + result.resize(stringSize); } catch (std::bad_alloc& ba) { CORE_LOG_ERROR("[FileManager] bad_alloc caught: " + static_cast(ba.what())); - return std::string("Error!"); + return unexpected(FileManager::Error::TooBigFile); } - if (fread(buffer, sizeof(char), stringSize, file) < stringSize) { - delete[] buffer; + if (fread(result.data(), sizeof(char), stringSize, file) < stringSize) { fclose(file); CORE_LOG_ERROR("[FileManager] Could not read whole file: " + static_cast(filePath)); - return "[FileManager] Could not read whole file: " + static_cast(filePath); + return unexpected(FileManager::Error::Fail); } - buffer[stringSize] = '\0'; - std::string result(buffer); - delete[] buffer; fclose(file); return result; - } #ifdef LINUX - std::string FileManager::ReadBigFile(const char* filePath) { + expected FileManager::ReadBigFile(const char* filePath) { int fileDescriptor = open(filePath, O_RDONLY, S_IRUSR | S_IWUSR); struct stat sb{}; if (fstat(fileDescriptor, &sb) == -1) { CORE_LOG_WARN("[FileManager] Couldn't get size of the file. Check if the file exists at path: " + static_cast(filePath)); - return "[FileManager] Couldn't get size of the file. Check if the file exists at path: " + static_cast(filePath); + return unexpected(FileManager::Error::CantOpenFile); } auto* buffer = static_cast(mmap(nullptr, static_cast(sb.st_size), PROT_READ, MAP_PRIVATE, fileDescriptor, 0)); @@ -82,8 +76,8 @@ namespace Bald::Utils { return result; } -#else - std::string FileManager::ReadBigFile(const char *filePath) { +#if defined(WINDOWS) || defined(APPLE) + expected FileManager::ReadBigFile(const char *filePath) { CORE_LOG_INFO("[FILE_MANAGER] Error: Windows implementation is not done yet! Using slower reading method!"); return ReadSmallFile(filePath); } diff --git a/engine/src/core/utils/file_manager.h b/engine/src/core/utils/file_manager.h index b877e0d5..d3f080e1 100644 --- a/engine/src/core/utils/file_manager.h +++ b/engine/src/core/utils/file_manager.h @@ -5,6 +5,7 @@ #pragma once #include +#include "error/expected.h" namespace Bald::Utils { @@ -18,9 +19,15 @@ namespace Bald::Utils { /** * ENUM which determines size of file and therefor methods, which will be used to read it */ - enum class Size : char { + enum class Size : uint8_t { SMALL_FILE, BIG_FILE }; + + enum class Error : uint8_t { + Fail, + CantOpenFile, + TooBigFile + }; public: /** @@ -44,7 +51,7 @@ namespace Bald::Utils { * @return string */ - [[nodiscard]] static std::string ReadFile(const char* filePath, Size size); + [[nodiscard]] static expected ReadFile(const char* filePath, Size size = Size::SMALL_FILE); private: /** @@ -53,7 +60,7 @@ namespace Bald::Utils { * @param filePath Path to file * @return string */ - [[nodiscard]] static std::string ReadSmallFile(const char* filePath); + [[nodiscard]] static expected ReadSmallFile(const char* filePath); /** * @fn ReadBigFile @@ -61,7 +68,7 @@ namespace Bald::Utils { * @param filePath Path to file * @return string */ - [[nodiscard]] static std::string ReadBigFile(const char* filePath); + [[nodiscard]] static expected ReadBigFile(const char* filePath); }; } // END OF NAMESPACE Bald::Utils diff --git a/engine/tests/test_file_manager.cpp b/engine/tests/test_file_manager.cpp index 49a13cdf..aa4335ee 100644 --- a/engine/tests/test_file_manager.cpp +++ b/engine/tests/test_file_manager.cpp @@ -8,28 +8,32 @@ TEST(FileManager, GoodSmallFileOpening) { //NOLINT - std::string file_result = Bald::Utils::FileManager::ReadFile("../engine/test_file_manager.txt", Bald::Utils::FileManager::Size::SMALL_FILE); - - EXPECT_EQ("plik testowy\ndo odczytu", file_result); + auto file_result = Bald::Utils::FileManager::ReadFile("../engine/test_file_manager.txt", Bald::Utils::FileManager::Size::SMALL_FILE); + EXPECT_TRUE(file_result.isValid()); + EXPECT_EQ("plik testowy\ndo odczytu", file_result.value()); + EXPECT_TRUE(file_result); } TEST(FileManager, GoodBigFileOpening) { //NOLINT - std::string file_result = Bald::Utils::FileManager::ReadFile("../engine/test_file_manager.txt", Bald::Utils::FileManager::Size::BIG_FILE); - - EXPECT_EQ("plik testowy\ndo odczytu", file_result); + auto file_result = Bald::Utils::FileManager::ReadFile("../engine/test_file_manager.txt", Bald::Utils::FileManager::Size::BIG_FILE); + EXPECT_TRUE(file_result.isValid()); + EXPECT_EQ("plik testowy\ndo odczytu", file_result.value()); + EXPECT_TRUE(file_result); } TEST(FileManager, WrongSmallFileOpening) { //NOLINT - - std::string file_result = Bald::Utils::FileManager::ReadFile("no_such_file.cpp", Bald::Utils::FileManager::Size::SMALL_FILE); - - EXPECT_EQ("[FileManager] Couldn't open the file at path: no_such_file.cpp", file_result); + using namespace Bald::Utils; + auto data = FileManager::ReadFile("no_such_file.cpp", Bald::Utils::FileManager::Size::SMALL_FILE); + EXPECT_FALSE(data.isValid()); + EXPECT_EQ(FileManager::Error::CantOpenFile, data.error()); + EXPECT_FALSE(data); } TEST(FileManager, WrongBigFileOpening) { //NOLINT - - std::string file_result = Bald::Utils::FileManager::ReadFile("no_such_file.cpp", Bald::Utils::FileManager::Size::BIG_FILE); - - EXPECT_EQ("[FileManager] Couldn't get size of the file. Check if the file exists at path: no_such_file.cpp", file_result); + using namespace Bald::Utils; + auto data = Bald::Utils::FileManager::ReadFile("no_such_file.cpp", Bald::Utils::FileManager::Size::BIG_FILE); + EXPECT_FALSE(data.isValid()); + EXPECT_EQ(FileManager::Error::CantOpenFile, data.error()); + EXPECT_FALSE(data); } diff --git a/engine/vendor/imgui b/engine/vendor/imgui index 9fa3163d..efa73cae 160000 --- a/engine/vendor/imgui +++ b/engine/vendor/imgui @@ -1 +1 @@ -Subproject commit 9fa3163dd8a60dedd2da3c26955a670a0349d45f +Subproject commit efa73cae865fa5ec4d59dfb7681b1e77df0506dd