From 0b473c0f8ad30dc6bf0f786ec3d3c29540dfe53e Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Mon, 6 Apr 2026 02:22:28 -0500 Subject: [PATCH 01/18] Made errors mostly work as hoped --- CMakeLists.txt | 3 +- engine/NBCore/ANSITerm.hpp | 6 - engine/NBCore/CMakeLists.txt | 8 +- engine/NBCore/Errors.hpp | 225 +++++++++++++++++--------- engine/NBCore/Types.hpp | 25 --- engine/NBCore/Utils.hpp | 45 ++++++ engine/NBCore/src/Errors.cpp | 11 +- engine/NBCore/src/Processes.cpp | 1 - engine/NBCore/src/Utils.cpp | 23 +++ engine/NBCore/tests/CMakeLists.txt | 5 +- engine/NBCore/tests/testErrors.cpp | 31 ++-- engine/NBCore/tests/testProcesses.cpp | 2 - engine/NBCore/tests/testUtils.cpp | 41 +++++ 13 files changed, 284 insertions(+), 142 deletions(-) delete mode 100644 engine/NBCore/Types.hpp create mode 100644 engine/NBCore/Utils.hpp create mode 100644 engine/NBCore/src/Utils.cpp create mode 100644 engine/NBCore/tests/testUtils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f60158..65af2c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,13 +48,12 @@ if(NB_BUILD_TESTS) include(FetchContent) FetchContent_Declare( gtest - URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip + URL https://github.com/google/googletest/archive/refs/heads/main.zip ) if (WIN32) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(gtest) endif() - include(GoogleTest) set(GTEST_COLOR ON) set(GLFW_BUILD_TESTS ON CACHE BOOL "" FORCE) endif() diff --git a/engine/NBCore/ANSITerm.hpp b/engine/NBCore/ANSITerm.hpp index b74ee7b..b729bac 100644 --- a/engine/NBCore/ANSITerm.hpp +++ b/engine/NBCore/ANSITerm.hpp @@ -2,16 +2,10 @@ #ifndef _NB_ANSI_TERM #define _NB_ANSI_TERM -#include -#include -#include #include #include -#include #include -#include "TypeTraits.hpp" - /* ----------- TECH DEBT ------------ Idk wtf to do here. This was originally to allow me to print diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index 6b105df..2260d5a 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,9 +1,8 @@ -include_directories(./.) - toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp - ./src/Processes.cpp ./src/Logger.cpp + ./src/Processes.cpp + ./src/Utils.cpp ) toAbsolutePath(NB_CORE_INCLUDE @@ -15,6 +14,7 @@ toAbsolutePath(NB_CORE_INCLUDE ./ThreadsafeQueue.hpp ./Types.hpp ./TypeTraits.hpp + ./Utils.hpp ) set(NB_CORE_SOURCE ${NB_CORE_SOURCE} PARENT_SCOPE) @@ -22,6 +22,8 @@ set(NB_CORE_INCLUDE ${NB_CORE_INCLUDE} PARENT_SCOPE) add_library(NBCore ${NB_CORE_SOURCE}) +target_include_directories(NBCore PUBLIC ./.) + if (NB_BUILD_TESTS) add_subdirectory(./tests) endif() \ No newline at end of file diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index a893b9b..49bedd1 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -3,10 +3,11 @@ #define _NB_ERROR #include -#include +#include #include #include #include +#include "Utils.hpp" #ifndef THROW_WITH_INFO #ifdef CODE_ERROR_LOCATIONS @@ -31,109 +32,173 @@ typedef std::unordered_map ErrorCodeMap; template class ErrorBase : public std::exception { public: - ErrorBase( - const unsigned int code, - unsigned int line=0, - std::string filename="" - ) noexcept : ErrorBase( - code, - ErrorBase::lookup(code), - line, - filename - ) {} - ErrorBase( - const unsigned int code, - const std::exception& trace, - unsigned int line=0, - std::string filename="" - ) noexcept : ErrorBase( - code, - ErrorBase::lookup(code), - trace, - line, - filename - ) {} + ErrorBase(const ErrorBase&) = default; + ErrorBase& operator=(const ErrorBase&) = delete; - static std::string lookup(unsigned int); - unsigned int code() const noexcept { - return static_cast(this)->_code; - }; - virtual const char* what() const noexcept override final { return _msg.c_str(); }; + virtual const char* what() const noexcept override final { + std::string ret = this->msg; + const std::string replace = nb::NEWLINE + "\t"; + if (trace) { + ret += replace + find_and_replace( + std::string(trace->what()), + nb::NEWLINE, + replace + ); + } + const std::string& ret_ref = ret; + return ret_ref.c_str(); + } + + static const std::string type; + static const ErrorCodeMap ErrorMessages; + + const unsigned int code; + const std::string msg; + const std::exception* trace; protected: - ErrorBase() = default; + ErrorBase() = delete; + + template < + typename TraceType=std::exception, + std::enable_if_t, bool> = true + > ErrorBase( - const unsigned int code, - std::string msg, - unsigned int line=0, - std::string filename="" - ) noexcept : _code{code}, _msg{""} { + const unsigned int code_, + std::string msg_, + const TraceType* trace_=nullptr, + unsigned int line_=0, + std::string filename_="" + ) noexcept : + code(code_), + msg(msg_), + trace{static_cast(trace_ ? new TraceType(*trace_) : nullptr) } + { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " "a class member." ); - static_assert(std::is_enum_v, "enum ErrorCodes must be a class member."); - static_assert(std::is_same, unsigned int>::value, - "enum ErrorCodes must be of underlying type unsigned int." + static_assert(std::is_enum_v, "enum Codes must be a class member."); + static_assert(std::is_same, unsigned int>::value, + "enum Codes must be of underlying type unsigned int." ); static_assert(std::is_same::value, "const std::string type must be a class member." ); - - _msg += std::string(ErrorType::type); - _msg += "[" + std::to_string(_code) + "]"; - if (line && filename.size()) { - _msg += " in \'" + filename + "\':" + std::to_string(line); - } - _msg += "\n " + msg; - } - ErrorBase( - const unsigned int code, - std::string msg, - const std::exception& trace, - unsigned int line=0, - std::string filename="" - ) noexcept : ErrorBase(code, msg, line, filename) { - std::string what_msg(trace.what()); - std::string::size_type newline_pos=-1; - while((newline_pos=what_msg.find("\n", newline_pos+1))!= std::string::npos) { - what_msg.replace(newline_pos, 1, "\n "); - } - _msg += "\n Trace - " + what_msg; + static_assert(std::is_base_of::value, + "`trace_` must be a pointer to a child object of std::exception." + ); } - - unsigned int _code; - std::string _msg; + + template < + typename TraceType, + std::enable_if_t, bool> = true + > + ErrorBase( + const unsigned int& code_, + const TraceType& trace_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + &trace_, + line_, + filename_ + ) {} + + template < + typename TraceType, + std::enable_if_t, bool> = true + > + ErrorBase( + const std::string& msg_, + const TraceType& trace_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + 0, + msg_, + &trace_, + line_, + filename_ + ) {} + + ErrorBase( + const unsigned int& code_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + static_cast(nullptr), + line_, + filename_ + ) {} + + ErrorBase( + const std::string& msg_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + 0, + msg_, + nullptr, + line_, + filename_ + ) {} + +}; +template +const std::string ErrorBase::type = ErrorType::type; +template +const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; + +class DefaultError {DefaultError() = default;}; + +template +class Error; + +template<> +class Error; + +template +class Error : public ErrorBase { + using Base = ErrorBase; +public: + template + Error(Args... T) : Base(T...) {} + + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; + using Base::type; + using Base::ErrorMessages; + + friend ErrorBase; }; -class Error : public ErrorBase { +template<> +class Error : public ErrorBase> { + using Base = ErrorBase>; public: - enum ErrorCodes : unsigned int { + using Base::Base; + Error() : Base(0) {} + + enum Codes : unsigned int { GENERAL, UNDEFINED, BADERRORCODE }; - using ErrorBase::ErrorBase; + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; - friend ErrorBase; - -protected: static const std::string type; static const ErrorCodeMap ErrorMessages; - }; -template -std::string ErrorBase::lookup(unsigned int code) { - for (auto kv : ErrorType::ErrorMessages) { - if (kv.first==code) { - return std::string(kv.second); - } - } - - throw Error(Error::ErrorCodes::BADERRORCODE); -} - } // namespace nb - #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/Types.hpp b/engine/NBCore/Types.hpp deleted file mode 100644 index 293bdb5..0000000 --- a/engine/NBCore/Types.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#ifndef _NB_CORE_TYPES -#define _NB_CORE_TYPES - -#include - -namespace nb { - -template -T swapEndian(const T& val) { - T ret; - const int size = sizeof(T); - auto retLoc = static_cast(&ret); - auto valLoc = static_cast(&val); - - for (int i = 0; i < size; ++i) { - memcpy(retLoc+i, valLoc+(size-i-1), 1); - } - return ret; -} - -using ByteVector = std::vector; - -} // namespace nb -#endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp new file mode 100644 index 0000000..3151183 --- /dev/null +++ b/engine/NBCore/Utils.hpp @@ -0,0 +1,45 @@ +#pragma once +#ifndef _NB_CORE_TYPES +#define _NB_CORE_TYPES + +#include +#include +#include + +namespace nb { + +#ifdef _NB_TARGET_WINDOWS + const std::string NEWLINE("\r\n"); +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX + const std::string NEWLINE("\n"); +#endif // _NB_TARGET_LINUX + +template +struct ConstexprMap { + template + constexpr ConstexprMap(Input inp) : _data{inp} {} + +protected: + const std::array, N> _data; +}; + +/* template +T swap_endian(const T& val) { + T ret; + const int size = sizeof(T); + auto retLoc = static_cast(&ret); + auto valLoc = static_cast(&val); + + for (int i = 0; i < size; ++i) { + memcpy(retLoc+i, valLoc+(size-i-1), 1); + } + return ret; +} */ + +std::string find_and_replace(const std::string& original, const std::string& find, const std::string& replace); + +// using ByteVector = std::vector; + +} // namespace nb +#endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp index 544346a..952f772 100644 --- a/engine/NBCore/src/Errors.cpp +++ b/engine/NBCore/src/Errors.cpp @@ -2,11 +2,12 @@ namespace nb { -const std::string Error::type = "Error"; -const ErrorCodeMap Error::ErrorMessages = { - {ErrorCodes::GENERAL, "General std::exception."}, - {ErrorCodes::UNDEFINED, "Undefined / general error."}, - {ErrorCodes::BADERRORCODE, "Unrecognized error code."} +const std::string Error::type = "nb::Error"; + +const ErrorCodeMap Error::ErrorMessages = { + {Error::Codes::GENERAL, "General std::exception."}, + {Error::Codes::UNDEFINED, "Undefined / general error."}, + {Error::Codes::BADERRORCODE, "Unrecognized error code."} }; } diff --git a/engine/NBCore/src/Processes.cpp b/engine/NBCore/src/Processes.cpp index dabf222..744d96d 100644 --- a/engine/NBCore/src/Processes.cpp +++ b/engine/NBCore/src/Processes.cpp @@ -7,7 +7,6 @@ #endif // _NB_TARGET_LINUX #include "Processes.hpp" -#include "Types.hpp" namespace nb { diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp new file mode 100644 index 0000000..f060189 --- /dev/null +++ b/engine/NBCore/src/Utils.cpp @@ -0,0 +1,23 @@ +#include +#include "Utils.hpp" + + +std::string nb::find_and_replace(const std::string& original, const std::string& find, const std::string& replace) { + std::string ret = original; + + std::size_t find_len = find.length(); + std::size_t replace_len = replace.length(); + std::size_t currpos = 0; + std::size_t lastpos = 0; + while(true) { + lastpos = currpos; + currpos = original.find(find, lastpos); + if (currpos == std::string::npos) { + break; + } + ret = ret.erase(currpos, find_len); + ret = ret.insert(currpos, replace); + currpos += replace_len; + } + return ret; +} \ No newline at end of file diff --git a/engine/NBCore/tests/CMakeLists.txt b/engine/NBCore/tests/CMakeLists.txt index d3ad479..02c31c7 100644 --- a/engine/NBCore/tests/CMakeLists.txt +++ b/engine/NBCore/tests/CMakeLists.txt @@ -4,8 +4,9 @@ if (NB_BUILD_TESTS) enable_testing() include(GoogleTest) add_executable(TestCore - testErrors.cpp - testProcesses.cpp + ./testErrors.cpp + #./testProcesses.cpp + ./testUtils.cpp ) target_link_libraries(TestCore NBCore diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 7d79ee9..6b1c21f 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -3,36 +3,35 @@ #include "Errors.hpp" #include #include -#include -#include "Logger.hpp" using namespace nb; -class TestError : public ErrorBase { +class TestError : public Error { + using Base = Error; public: - using ErrorBase::ErrorBase; + using Base::Base; + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; - enum ErrorCodes : unsigned int { + enum Codes : unsigned int { A, B, C, D }; + static const std::string type; - static const ErrorCodeMap ErrorMessages; + static const nb::ErrorCodeMap ErrorMessages; }; const std::string TestError::type="TestError"; const ErrorCodeMap TestError::ErrorMessages{ - {TestError::ErrorCodes::A, "Hey!"}, - {TestError::ErrorCodes::B, "How"}, - {TestError::ErrorCodes::C, "You"}, - {TestError::ErrorCodes::D, "Doin"} + {TestError::Codes::A, "Hey!"}, + {TestError::Codes::B, "How"}, + {TestError::Codes::C, "You"}, + {TestError::Codes::D, "Doin"} }; TEST(ErrorTest, Test) { - EXPECT_EQ(1, 1); - - std::stringstream sstream; - - ASSERT_TRUE(nb::logger.isRunning()); - nb::logger.log("Hey!"); + std::cout << TestError(0, TestError(1, TestError(2))).what(); } \ No newline at end of file diff --git a/engine/NBCore/tests/testProcesses.cpp b/engine/NBCore/tests/testProcesses.cpp index 3e220b8..cee1e90 100644 --- a/engine/NBCore/tests/testProcesses.cpp +++ b/engine/NBCore/tests/testProcesses.cpp @@ -1,8 +1,6 @@ #define CODE_ERROR_LOCATIONS #include - -#include #include "Processes.hpp" #include diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp new file mode 100644 index 0000000..1ef1969 --- /dev/null +++ b/engine/NBCore/tests/testUtils.cpp @@ -0,0 +1,41 @@ +#define CODE_ERROR_LOCATIONS + +#include "Utils.hpp" +#include + +namespace nb { + +TEST(UtilsTest, Test) { + ASSERT_STREQ( + find_and_replace("Jeff", "e", "efe").c_str(), + "Jefeff" + ); + + auto tmp = find_and_replace("Naif", "a", "afa"); + ASSERT_STREQ( + find_and_replace(tmp, "i", "ifi").c_str(), + "Nafaifif" + ); + + tmp = find_and_replace("aeiou", "a", "afa"); + tmp = find_and_replace(tmp, "e", "efe"); + tmp = find_and_replace(tmp, "i", "ifi"); + tmp = find_and_replace(tmp, "o", "ofo"); + tmp = find_and_replace(tmp, "u", "ufu"); + ASSERT_STREQ( + tmp.c_str(), + "afaefeifiofoufu" + ); + + tmp = find_and_replace(tmp, "afa", "a"); + tmp = find_and_replace(tmp, "efe", "e"); + tmp = find_and_replace(tmp, "ifi", "i"); + tmp = find_and_replace(tmp, "ofo", "o"); + tmp = find_and_replace(tmp, "ufu", "u"); + ASSERT_STREQ( + tmp.c_str(), + "aeiou" + ); +} + +} // namespace nb \ No newline at end of file -- 2.43.0 From fd7d36e4be144cf7941a2fb81e9a4c990e270ca8 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:44:19 -0500 Subject: [PATCH 02/18] Added more Util tests and str-wstr related changes to util functions --- engine/NBCore/Utils.hpp | 66 +++++++++++++++++++++---- engine/NBCore/src/Utils.cpp | 31 +++++------- engine/NBCore/tests/testUtils.cpp | 81 +++++++++++++++++++++++++++++-- 3 files changed, 145 insertions(+), 33 deletions(-) diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index 3151183..e51d3f5 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -1,4 +1,6 @@ #pragma once +#include +#include #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES @@ -9,20 +11,65 @@ namespace nb { #ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE("\r\n"); + const std::string NEWLINE; + const std::wstring WNEWLINE; #endif // _NB_TARGET_WINDOWS #ifdef _NB_TARGET_LINUX - const std::string NEWLINE("\n"); + const std::string NEWLINE; + const std::wstring WNEWLINE; #endif // _NB_TARGET_LINUX -template -struct ConstexprMap { - template - constexpr ConstexprMap(Input inp) : _data{inp} {} +template +std::enable_if_t, std::wstring> str_to_wstr(const T& str) { + std::mbstate_t state = std::mbstate_t(); + const char* cstr = std::string(str).c_str(); + std::size_t wlen = 1 + std::mbsrtowcs(nullptr, &cstr, 0, &state); + wchar_t* c_wstr= new wchar_t[wlen]; + std::mbsrtowcs(c_wstr, &cstr, wlen, &state); + std::wstring ret(c_wstr, wlen); + delete[] c_wstr; + return ret; +} -protected: - const std::array, N> _data; -}; +template +std::enable_if_t, std::string> wstr_to_str(const T& wstr) { + const wchar_t* c_wstr = std::wstring(wstr).c_str(); + std::size_t strlen = 1 + std::wcstombs(nullptr, c_wstr, 0); + char* c_str= new char[strlen]; + std::wcstombs(c_str, c_wstr, strlen); + std::string ret(c_str, strlen); + delete[] c_str; + return ret; +} + +template +T find_and_replace( + const A& original, + const B& find, + const C& replace +) { + const T& original_t = T(original); + const T& find_t = T(find); + const T& replace_t = T(replace); + + T ret = original_t; + + std::size_t find_len = find_t.length(); + std::size_t replace_len = replace_t.length(); + std::size_t currpos = 0; + std::size_t lastpos = 0; + while(true) { + lastpos = currpos; + currpos = original_t.find(find_t, lastpos); + if (currpos == T::npos) { + break; + } + ret = ret.erase(currpos, find_len); + ret = ret.insert(currpos, replace_t); + currpos += replace_len; + } + return ret; +} /* template T swap_endian(const T& val) { @@ -37,7 +84,6 @@ T swap_endian(const T& val) { return ret; } */ -std::string find_and_replace(const std::string& original, const std::string& find, const std::string& replace); // using ByteVector = std::vector; diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index f060189..f94f897 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1,23 +1,14 @@ +#include +#include #include + #include "Utils.hpp" - -std::string nb::find_and_replace(const std::string& original, const std::string& find, const std::string& replace) { - std::string ret = original; - - std::size_t find_len = find.length(); - std::size_t replace_len = replace.length(); - std::size_t currpos = 0; - std::size_t lastpos = 0; - while(true) { - lastpos = currpos; - currpos = original.find(find, lastpos); - if (currpos == std::string::npos) { - break; - } - ret = ret.erase(currpos, find_len); - ret = ret.insert(currpos, replace); - currpos += replace_len; - } - return ret; -} \ No newline at end of file +#ifdef _NB_TARGET_WINDOWS + const std::string NEWLINE("\r\n"); + const std::wstring WNEWLINE(L"\r\n"); +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX + const std::string NEWLINE("\n"); + const std::wstring WNEWLINE(L"\n"); +#endif // _NB_TARGET_LINUX diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index 1ef1969..042e7a0 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -1,17 +1,20 @@ +#include #define CODE_ERROR_LOCATIONS -#include "Utils.hpp" #include +#include +#include "Utils.hpp" + namespace nb { -TEST(UtilsTest, Test) { +TEST(UtilsTest, TestFindAndReplace) { ASSERT_STREQ( find_and_replace("Jeff", "e", "efe").c_str(), "Jefeff" ); - auto tmp = find_and_replace("Naif", "a", "afa"); + std::string tmp = find_and_replace("Naif", "a", "afa"); ASSERT_STREQ( find_and_replace(tmp, "i", "ifi").c_str(), "Nafaifif" @@ -38,4 +41,76 @@ TEST(UtilsTest, Test) { ); } +TEST(UtilsTest, TestFindAndReplaceWstr) { + ASSERT_STREQ( + find_and_replace(L"Jeff", L"e", L"efe").c_str(), + L"Jefeff" + ); + + std::wstring tmp = find_and_replace(L"Naif", L"a", L"afa"); + ASSERT_STREQ( + find_and_replace(tmp, L"i", L"ifi").c_str(), + L"Nafaifif" + ); + + tmp = find_and_replace(L"aeiou", L"a", L"afa"); + tmp = find_and_replace(tmp, L"e", L"efe"); + tmp = find_and_replace(tmp, L"i", L"ifi"); + tmp = find_and_replace(tmp, L"o", L"ofo"); + tmp = find_and_replace(tmp, L"u", L"ufu"); + ASSERT_STREQ( + tmp.c_str(), + L"afaefeifiofoufu" + ); + + tmp = find_and_replace(tmp, L"afa", L"a"); + tmp = find_and_replace(tmp, L"efe", L"e"); + tmp = find_and_replace(tmp, L"ifi", L"i"); + tmp = find_and_replace(tmp, L"ofo", L"o"); + tmp = find_and_replace(tmp, L"ufu", L"u"); + ASSERT_STREQ( + tmp.c_str(), + L"aeiou" + ); +} + +TEST(UtilsTest, TestWstrToStr) { + ASSERT_STREQ( + nb::wstr_to_str(L"Hi!").c_str(), + "Hi!" + ); + ASSERT_STREQ( + nb::wstr_to_str(L"Naif").c_str(), + "Naif" + ); + ASSERT_STREQ( + nb::wstr_to_str(L"\r\r\r\n").c_str(), + "\r\r\r\n" + ); + ASSERT_STREQ( + nb::wstr_to_str(L"Naif\ttalks\r\ra\t\nlot").c_str(), + "Naif\ttalks\r\ra\t\nlot" + ); +} + +TEST(UtilsTest, TestStrToWstr) { + ASSERT_STREQ( + nb::str_to_wstr("Hi!").c_str(), + L"Hi!" + ); + ASSERT_STREQ( + nb::str_to_wstr("Naif").c_str(), + L"Naif" + ); + ASSERT_STREQ( + nb::str_to_wstr("\r\r\r\n").c_str(), + L"\r\r\r\n" + ); + ASSERT_STREQ( + nb::str_to_wstr("Naif\ttalks\r\ra\t\nlot").c_str(), + L"Naif\ttalks\r\ra\t\nlot" + ); +} + + } // namespace nb \ No newline at end of file -- 2.43.0 From e23e062e5899f3ba12bfd1482f57a1e61a59b55a Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:31:11 -0500 Subject: [PATCH 03/18] Man im so tired This is wrong but I can taste it, im close --- engine/NBCore/CMakeLists.txt | 2 +- engine/NBCore/Errors.hpp | 98 +++++++++++++++++++++++------- engine/NBCore/TypeTraits.hpp | 40 +++++++++++- engine/NBCore/Utils.hpp | 33 ++++------ engine/NBCore/src/Errors.cpp | 5 +- engine/NBCore/src/Utils.cpp | 16 ++--- engine/NBCore/tests/testErrors.cpp | 14 ++++- engine/NBCore/tests/testUtils.cpp | 33 ++++++++++ 8 files changed, 182 insertions(+), 59 deletions(-) diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index 2260d5a..b457870 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,6 +1,6 @@ toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp - ./src/Logger.cpp +# ./src/Logger.cpp ./src/Processes.cpp ./src/Utils.cpp ) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 49bedd1..6517341 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -1,4 +1,5 @@ #pragma once +#include #ifndef _NB_ERROR #define _NB_ERROR @@ -6,10 +7,11 @@ #include #include #include +#include "TypeTraits.hpp" #include #include "Utils.hpp" -#ifndef THROW_WITH_INFO +/* #ifndef THROW_WITH_INFO #ifdef CODE_ERROR_LOCATIONS #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) #else @@ -23,30 +25,43 @@ #else #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) #endif // LOGGING -#endif // THROW +#endif // THROW */ namespace nb { typedef std::unordered_map ErrorCodeMap; +template +using has_type = decltype(T::type); + +template +struct NBErrorWhatString; + +class ErrorBase_what_str_impl : public std::exception { + template + T what_str() const; + + template <> + virtual std::wstring what_str() const; + + template<> + virtual std::string what_str() const; +}; + template -class ErrorBase : public std::exception { +class ErrorBase : public ErrorBase_what_str_impl { public: ErrorBase(const ErrorBase&) = default; ErrorBase& operator=(const ErrorBase&) = delete; + template + inline const StringType what_str() const noexcept { + return NBErrorWhatString::what(*this); + } + virtual const char* what() const noexcept override final { - std::string ret = this->msg; - const std::string replace = nb::NEWLINE + "\t"; - if (trace) { - ret += replace + find_and_replace( - std::string(trace->what()), - nb::NEWLINE, - replace - ); - } - const std::string& ret_ref = ret; - return ret_ref.c_str(); + const std::string& ret = what_str(); + return ret.c_str(); } static const std::string type; @@ -54,7 +69,8 @@ public: const unsigned int code; const std::string msg; - const std::exception* trace; + const std::shared_ptr trace; + const bool traceIsNBError; protected: ErrorBase() = delete; @@ -72,7 +88,8 @@ protected: ) noexcept : code(code_), msg(msg_), - trace{static_cast(trace_ ? new TraceType(*trace_) : nullptr) } + trace{trace_ ? std::make_shared(*trace_) : nullptr}, + traceIsNBError( trace_ ? is_detected::value : false) { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " @@ -148,19 +165,58 @@ protected: filename_ ) {} + std::string (ErrorBase::*_trace_what_str)(); + std::wstring (ErrorBase::*_trace_what_wstr)(); }; template const std::string ErrorBase::type = ErrorType::type; template const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; -class DefaultError {DefaultError() = default;}; +template +struct NBErrorWhatString { + inline static const std::wstring what(const ErrorBase& err) noexcept { + std::wstring ret = nb::str_to_wstr(err.msg); + const std::wstring replace = nb::WNEWLINE + L"┗-"; + if (err.trace) { + std::wstring trace_msg; + if (err.traceIsNBError) { + trace_msg = std::static_pointer_cast(err.trace)->template what_str(); + } else { + trace_msg = nb::str_to_wstr(std::string(err.trace->what())); + } + trace_msg = find_and_replace(trace_msg, L"┗", L"-"); + ret += replace + find_and_replace( + trace_msg, + nb::WNEWLINE, + replace + ); + } + return ret; + } +}; -template +template +struct NBErrorWhatString { + inline static const std::string what(const ErrorBase& err) noexcept { + std::string ret = err.msg; + const std::string replace = nb::NEWLINE+" "; + if (err.trace) { + ret += replace + find_and_replace( + std::string(err.trace->what()), + nb::NEWLINE, + replace + ); + } + return ret; + } +}; + +template class Error; template<> -class Error; +class Error; template class Error : public ErrorBase { @@ -180,8 +236,8 @@ public: }; template<> -class Error : public ErrorBase> { - using Base = ErrorBase>; +class Error : public ErrorBase> { + using Base = ErrorBase>; public: using Base::Base; Error() : Base(0) {} diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index 5226e94..a1e7502 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -6,7 +6,43 @@ namespace nb { -template +namespace detail { + template < + class Default, + class AlwaysVoid, + template class Op, + class... Args + > + struct detector { + using value = std::false_type; + using type = Default; + }; + + template < + class Default, + template class Op, + class... Args + > + struct detector>, Op, Args...> { + using value = std::true_type; + using type = Op; + }; +} // namespace detail + +struct NoneType{}; + +template < + template class Op, + class... Args +> +using is_detected = typename detail::detector::value; + +template +void stream(Stream& s, Args&&... args) { + (s << ... << args); +} + +/*template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} @@ -68,7 +104,7 @@ struct PackIsSameType { template struct PackIsSameType { const bool value = std::is_base_of::value && PackIsSameType::value; -}; +};*/ } // namespace nb diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index e51d3f5..96194d3 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -4,40 +4,33 @@ #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES -#include -#include #include namespace nb { #ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE; - const std::wstring WNEWLINE; + const std::string NEWLINE = "\r\n"; + const std::wstring WNEWLINE = L"\r\n"; #endif // _NB_TARGET_WINDOWS #ifdef _NB_TARGET_LINUX - const std::string NEWLINE; - const std::wstring WNEWLINE; + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; #endif // _NB_TARGET_LINUX template -std::enable_if_t, std::wstring> str_to_wstr(const T& str) { - std::mbstate_t state = std::mbstate_t(); - const char* cstr = std::string(str).c_str(); - std::size_t wlen = 1 + std::mbsrtowcs(nullptr, &cstr, 0, &state); - wchar_t* c_wstr= new wchar_t[wlen]; - std::mbsrtowcs(c_wstr, &cstr, wlen, &state); - std::wstring ret(c_wstr, wlen); - delete[] c_wstr; +std::enable_if_t, std::wstring> str_to_wstr(const T& in) { + std::string str(in); + std::wstring ret(str.begin(), str.end()); return ret; } template -std::enable_if_t, std::string> wstr_to_str(const T& wstr) { - const wchar_t* c_wstr = std::wstring(wstr).c_str(); - std::size_t strlen = 1 + std::wcstombs(nullptr, c_wstr, 0); - char* c_str= new char[strlen]; - std::wcstombs(c_str, c_wstr, strlen); - std::string ret(c_str, strlen); +std::enable_if_t, std::string> wstr_to_str(const T& in) { + std::wstring wstr(in); + std::size_t wstrlen = wstr.length(); + char* c_str= new char[wstrlen]; + std::wcstombs(c_str, wstr.c_str(), wstrlen); + std::string ret(c_str, wstrlen); delete[] c_str; return ret; } diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp index 952f772..43b6227 100644 --- a/engine/NBCore/src/Errors.cpp +++ b/engine/NBCore/src/Errors.cpp @@ -1,10 +1,11 @@ #include "Errors.hpp" +#include "TypeTraits.hpp" namespace nb { -const std::string Error::type = "nb::Error"; +const std::string Error::type = "nb::Error"; -const ErrorCodeMap Error::ErrorMessages = { +const ErrorCodeMap Error::ErrorMessages = { {Error::Codes::GENERAL, "General std::exception."}, {Error::Codes::UNDEFINED, "Undefined / general error."}, {Error::Codes::BADERRORCODE, "Unrecognized error code."} diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index f94f897..336d3b6 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1,14 +1,8 @@ -#include -#include #include - #include "Utils.hpp" -#ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE("\r\n"); - const std::wstring WNEWLINE(L"\r\n"); -#endif // _NB_TARGET_WINDOWS -#ifdef _NB_TARGET_LINUX - const std::string NEWLINE("\n"); - const std::wstring WNEWLINE(L"\n"); -#endif // _NB_TARGET_LINUX +template<> +std::wstring nb::str_to_wstr(const std::string& in) { + std::wstring ret(in.begin(), in.end()); + return ret; +} diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 6b1c21f..6c778b7 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -1,8 +1,11 @@ #define CODE_ERROR_LOCATIONS -#include "Errors.hpp" #include + +#include "Errors.hpp" #include +#include +#include "TypeTraits.hpp" using namespace nb; @@ -33,5 +36,12 @@ const ErrorCodeMap TestError::ErrorMessages{ TEST(ErrorTest, Test) { - std::cout << TestError(0, TestError(1, TestError(2))).what(); + auto err = TestError(0, TestError(1)); + nb::stream(std::cout, + "len string: ", err.what_str().length(), "\n", + "len wstring: ", err.what_str().length(), "\n" + ); + nb::stream(std::wcout, + err.what_str(), L"\n" + ); } \ No newline at end of file diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index 042e7a0..f9188a1 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -4,6 +4,7 @@ #include #include +#include "TypeTraits.hpp" #include "Utils.hpp" namespace nb { @@ -112,5 +113,37 @@ TEST(UtilsTest, TestStrToWstr) { ); } +struct A { bool x(); }; +struct B { bool y(); }; +struct C { bool x(); bool y; }; +struct D : C {}; + +template +using has_x = decltype(T::x); + +template +using has_y = decltype(T::y); + +TEST(UtilsTest, TestIsDetected) { + auto ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_FALSE(ret); + + ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_FALSE(ret); + + ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_TRUE(ret); + + ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_TRUE(ret); +} } // namespace nb \ No newline at end of file -- 2.43.0 From e1c456bfe43c7d7bd07ff212af8452583ba02247 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:41:01 -0500 Subject: [PATCH 04/18] I mean it compiled --- engine/NBCore/Errors.hpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 6517341..1f636f6 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -38,14 +38,9 @@ template struct NBErrorWhatString; class ErrorBase_what_str_impl : public std::exception { - template - T what_str() const; - - template <> - virtual std::wstring what_str() const; - - template<> - virtual std::string what_str() const; +public: + virtual std::string what_str_impl() const = 0; + virtual std::wstring what_wstr_impl() const = 0; }; template @@ -165,8 +160,8 @@ protected: filename_ ) {} - std::string (ErrorBase::*_trace_what_str)(); - std::wstring (ErrorBase::*_trace_what_wstr)(); + std::string what_str_impl() const override final { return what_str(); } + std::wstring what_wstr_impl() const override final { return what_str(); } }; template const std::string ErrorBase::type = ErrorType::type; @@ -181,7 +176,8 @@ struct NBErrorWhatString { if (err.trace) { std::wstring trace_msg; if (err.traceIsNBError) { - trace_msg = std::static_pointer_cast(err.trace)->template what_str(); + // How can I access + trace_msg = std::static_pointer_cast(err.trace)->what_wstr_impl(); } else { trace_msg = nb::str_to_wstr(std::string(err.trace->what())); } -- 2.43.0 From fb695798e795e0468c964bfcce430c640bf0848d Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:33:33 -0500 Subject: [PATCH 05/18] nb::Error objects now working --- engine/NBCore/Errors.hpp | 166 +++++++++++++++-------------- engine/NBCore/TypeTraits.hpp | 5 - engine/NBCore/Utils.hpp | 36 ++++--- engine/NBCore/tests/testErrors.cpp | 13 +-- engine/NBCore/tests/testUtils.cpp | 1 - 5 files changed, 111 insertions(+), 110 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 1f636f6..e406347 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -1,11 +1,11 @@ #pragma once -#include #ifndef _NB_ERROR #define _NB_ERROR #include -#include +#include #include +#include #include #include "TypeTraits.hpp" #include @@ -34,44 +34,89 @@ typedef std::unordered_map ErrorCodeMap; template using has_type = decltype(T::type); -template -struct NBErrorWhatString; +template +class ErrorBase; -class ErrorBase_what_str_impl : public std::exception { +template<> +class ErrorBase : public std::exception { public: - virtual std::string what_str_impl() const = 0; - virtual std::wstring what_wstr_impl() const = 0; -}; - -template -class ErrorBase : public ErrorBase_what_str_impl { -public: - ErrorBase(const ErrorBase&) = default; - ErrorBase& operator=(const ErrorBase&) = delete; - - template - inline const StringType what_str() const noexcept { - return NBErrorWhatString::what(*this); - } - - virtual const char* what() const noexcept override final { - const std::string& ret = what_str(); - return ret.c_str(); - } - - static const std::string type; - static const ErrorCodeMap ErrorMessages; - const unsigned int code; const std::string msg; const std::shared_ptr trace; const bool traceIsNBError; + virtual inline std::string str() const noexcept = 0; + + virtual const char* what() const noexcept override final { + const std::string& ret = str(); + return ret.c_str(); + } + protected: - ErrorBase() = delete; + template < + typename TraceType = std::exception, + std::enable_if_t, bool> = true + > + ErrorBase( + const unsigned int& code_, + const std::string& msg_, + const std::shared_ptr trace_, + const unsigned int& line_, + std::string filename_ + ) noexcept : + code(code_), + msg(msg_), + trace{std::dynamic_pointer_cast(trace_)}, + traceIsNBError( trace_ ? is_detected::value : false) + { + static_assert(std::is_base_of::value, + "`trace_` must be a pointer to a child object of std::exception." + ); + } +}; + +template +class ErrorBase : public ErrorBase { + using Base = ErrorBase; +public: + ErrorBase(const ErrorBase&) = default; + ErrorBase& operator=(const ErrorBase&) = delete; + + virtual inline std::string str() const noexcept override { + std::string ret = msg; + if (trace) { + const std::string replace = nb::NEWLINE+" "; + std::string trace_msg; + if (traceIsNBError) { + trace_msg = std::static_pointer_cast(trace)->str(); + trace_msg = std::string(std::string_view(trace_msg).substr( + 0, trace_msg.length()-nb::NEWLINE.length() + )); + } else { + trace_msg = std::string(trace->what()); + } + ret += replace + "Trace: " + find_and_replace( + trace_msg, + nb::NEWLINE, + replace + ); + } + return ret + nb::NEWLINE; + } + + static const std::string type; + static const ErrorCodeMap ErrorMessages; + + using Base::code; + using Base::msg; + using Base::trace; + using Base::traceIsNBError; + +protected: + using Base::Base; template < - typename TraceType=std::exception, + typename TraceType = std::exception, std::enable_if_t, bool> = true > ErrorBase( @@ -80,12 +125,13 @@ protected: const TraceType* trace_=nullptr, unsigned int line_=0, std::string filename_="" - ) noexcept : - code(code_), - msg(msg_), - trace{trace_ ? std::make_shared(*trace_) : nullptr}, - traceIsNBError( trace_ ? is_detected::value : false) - { + ) : Base( + code_, + msg_, + trace_ ? std::make_shared(*trace_) : nullptr, + line_, + filename_ + ) { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " "a class member." @@ -97,9 +143,6 @@ protected: static_assert(std::is_same::value, "const std::string type must be a class member." ); - static_assert(std::is_base_of::value, - "`trace_` must be a pointer to a child object of std::exception." - ); } template < @@ -159,55 +202,12 @@ protected: line_, filename_ ) {} - - std::string what_str_impl() const override final { return what_str(); } - std::wstring what_wstr_impl() const override final { return what_str(); } }; template const std::string ErrorBase::type = ErrorType::type; template const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; -template -struct NBErrorWhatString { - inline static const std::wstring what(const ErrorBase& err) noexcept { - std::wstring ret = nb::str_to_wstr(err.msg); - const std::wstring replace = nb::WNEWLINE + L"┗-"; - if (err.trace) { - std::wstring trace_msg; - if (err.traceIsNBError) { - // How can I access - trace_msg = std::static_pointer_cast(err.trace)->what_wstr_impl(); - } else { - trace_msg = nb::str_to_wstr(std::string(err.trace->what())); - } - trace_msg = find_and_replace(trace_msg, L"┗", L"-"); - ret += replace + find_and_replace( - trace_msg, - nb::WNEWLINE, - replace - ); - } - return ret; - } -}; - -template -struct NBErrorWhatString { - inline static const std::string what(const ErrorBase& err) noexcept { - std::string ret = err.msg; - const std::string replace = nb::NEWLINE+" "; - if (err.trace) { - ret += replace + find_and_replace( - std::string(err.trace->what()), - nb::NEWLINE, - replace - ); - } - return ret; - } -}; - template class Error; @@ -221,6 +221,7 @@ public: template Error(Args... T) : Base(T...) {} + using Base::str; using Base::what; using Base::code; using Base::msg; @@ -242,6 +243,7 @@ public: GENERAL, UNDEFINED, BADERRORCODE }; + using Base::str; using Base::what; using Base::code; using Base::msg; diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index a1e7502..5277159 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -37,11 +37,6 @@ template < > using is_detected = typename detail::detector::value; -template -void stream(Stream& s, Args&&... args) { - (s << ... << args); -} - /*template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index 96194d3..01d6dac 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -1,16 +1,16 @@ #pragma once -#include -#include #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES +#include #include +#include namespace nb { #ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE = "\r\n"; - const std::wstring WNEWLINE = L"\r\n"; + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; #endif // _NB_TARGET_WINDOWS #ifdef _NB_TARGET_LINUX const std::string NEWLINE = "\n"; @@ -18,14 +18,14 @@ namespace nb { #endif // _NB_TARGET_LINUX template -std::enable_if_t, std::wstring> str_to_wstr(const T& in) { +std::enable_if_t, std::wstring> str_to_wstr(T in) { std::string str(in); std::wstring ret(str.begin(), str.end()); return ret; } template -std::enable_if_t, std::string> wstr_to_str(const T& in) { +std::enable_if_t, std::string> wstr_to_str(T in) { std::wstring wstr(in); std::size_t wstrlen = wstr.length(); char* c_str= new char[wstrlen]; @@ -35,11 +35,25 @@ std::enable_if_t, std::string> wst return ret; } +template +void stream(Stream& s, Args&&... args); + +template +void stream(Stream& s, Args&&... args) { + (s << ... << args); +} + +template +void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } + +template +void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } + template T find_and_replace( - const A& original, - const B& find, - const C& replace + A original, + B find, + C replace ) { const T& original_t = T(original); const T& find_t = T(find); @@ -50,10 +64,8 @@ T find_and_replace( std::size_t find_len = find_t.length(); std::size_t replace_len = replace_t.length(); std::size_t currpos = 0; - std::size_t lastpos = 0; while(true) { - lastpos = currpos; - currpos = original_t.find(find_t, lastpos); + currpos = ret.find(find_t, currpos); if (currpos == T::npos) { break; } diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 6c778b7..81187be 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -3,9 +3,8 @@ #include #include "Errors.hpp" -#include #include -#include "TypeTraits.hpp" +#include "Utils.hpp" using namespace nb; @@ -36,12 +35,6 @@ const ErrorCodeMap TestError::ErrorMessages{ TEST(ErrorTest, Test) { - auto err = TestError(0, TestError(1)); - nb::stream(std::cout, - "len string: ", err.what_str().length(), "\n", - "len wstring: ", err.what_str().length(), "\n" - ); - nb::stream(std::wcout, - err.what_str(), L"\n" - ); + auto err = TestError(0, TestError(1, TestError(2, TestError(3, TestError(2))))); + ASSERT_STREQ(err.what(), "Hey!\n Trace: How\n Trace: You\n Trace: Doin\n Trace: You\n"); } \ No newline at end of file diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index f9188a1..e097788 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -1,4 +1,3 @@ -#include #define CODE_ERROR_LOCATIONS #include -- 2.43.0 From 40cf079e9db9a188a3ad01c55ccad7aa5b483d6b Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:08:58 -0500 Subject: [PATCH 06/18] Added type traits and string utils --- engine/NBCore/CMakeLists.txt | 2 + engine/NBCore/DataSink.hpp | 2 +- engine/NBCore/Errors.hpp | 34 ++----- engine/NBCore/Logger.hpp | 40 +++++--- engine/NBCore/StringUtils.hpp | 142 +++++++++++++++++++++++++++++ engine/NBCore/TypeTraits.hpp | 38 +++++++- engine/NBCore/Utils.hpp | 72 --------------- engine/NBCore/src/Logger.cpp | 2 + engine/NBCore/src/StringUtils.cpp | 1 + engine/NBCore/src/Utils.cpp | 7 -- engine/NBCore/tests/testErrors.cpp | 1 - engine/NBCore/tests/testUtils.cpp | 2 +- 12 files changed, 218 insertions(+), 125 deletions(-) create mode 100644 engine/NBCore/StringUtils.hpp create mode 100644 engine/NBCore/src/StringUtils.cpp diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index b457870..9f67cd0 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -2,6 +2,7 @@ toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp # ./src/Logger.cpp ./src/Processes.cpp + ./src/StringUtils.cpp ./src/Utils.cpp ) @@ -11,6 +12,7 @@ toAbsolutePath(NB_CORE_INCLUDE ./Errors.hpp ./Logger.hpp ./Processes.hpp + ./StringUtils.hpp ./ThreadsafeQueue.hpp ./Types.hpp ./TypeTraits.hpp diff --git a/engine/NBCore/DataSink.hpp b/engine/NBCore/DataSink.hpp index 75cbad6..3aa0c50 100644 --- a/engine/NBCore/DataSink.hpp +++ b/engine/NBCore/DataSink.hpp @@ -77,7 +77,7 @@ public: bool isRunning() const noexcept override { return this->_running && (_runningThread!=nullptr); } - bool run() { + bool run() override { if (!type_ptr->isRunning()) { this->_running = true; _runningThread = std::make_shared([&]{ diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index e406347..d36f749 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -9,23 +9,7 @@ #include #include "TypeTraits.hpp" #include -#include "Utils.hpp" - -/* #ifndef THROW_WITH_INFO - #ifdef CODE_ERROR_LOCATIONS - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__) - #endif // CODE_ERROR_LOCATIONS -#endif // THROW_WITH_INFO - -#ifndef THROW - #ifdef LOGGING - #define THROW_WTIH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) - #endif // LOGGING -#endif // THROW */ +#include "StringUtils.hpp" namespace nb { @@ -83,9 +67,9 @@ public: ErrorBase& operator=(const ErrorBase&) = delete; virtual inline std::string str() const noexcept override { - std::string ret = msg; + std::string ret = msg + nb::NEWLINE; if (trace) { - const std::string replace = nb::NEWLINE+" "; + const std::string tabover = " "; std::string trace_msg; if (traceIsNBError) { trace_msg = std::static_pointer_cast(trace)->str(); @@ -95,13 +79,9 @@ public: } else { trace_msg = std::string(trace->what()); } - ret += replace + "Trace: " + find_and_replace( - trace_msg, - nb::NEWLINE, - replace - ); + ret += indent_strblock(trace_msg, tabover, tabover+"Trace: ")+nb::NEWLINE; } - return ret + nb::NEWLINE; + return ret; } static const std::string type; @@ -226,6 +206,7 @@ public: using Base::code; using Base::msg; using Base::trace; + using Base::traceIsNBError; using Base::type; using Base::ErrorMessages; @@ -245,10 +226,11 @@ public: using Base::str; using Base::what; + using Base::code; using Base::msg; using Base::trace; - + using Base::traceIsNBError; static const std::string type; static const ErrorCodeMap ErrorMessages; }; diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index e767eea..40919f6 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -2,15 +2,28 @@ #ifndef _NB_LOGGER #define _NB_LOGGER -#include #include -#include #include #include -#include #include #include +#ifndef THROW_WITH_INFO + #ifdef CODE_ERROR_LOCATIONS + #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) + #else + #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__) + #endif // CODE_ERROR_LOCATIONS +#endif // THROW_WITH_INFO + +#ifndef THROW + #ifdef LOGGING + #define THROW_WTIH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) + #else + #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) + #endif // LOGGING +#endif // THROW + #include "DataSink.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" @@ -23,14 +36,6 @@ typedef std::chrono::time_point< std::chrono::nanoseconds > LoggerTimePoint; -struct LogEvent{ - const LoggerTimePoint time; - const unsigned char lvl; - const std::string msg; - const std::thread::id tid; - const uint64_t pid; -}; - typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); typedef std::unordered_map LogProcessFunctionMap; @@ -41,7 +46,7 @@ class LoggerBase using LoggerType = Logger; using Base = MultithreadedDataProcessor; public: - bool run() { + bool run() override { if (!type_ptr->isRunning()) { this->_running = true; this->_runningThread = std::make_shared([&]{ @@ -62,6 +67,14 @@ private: LoggerType* type_ptr = static_cast(this); }; +struct LogEvent{ + const LoggerTimePoint time; + const unsigned char lvl; + const std::string msg; + const std::thread::id tid; + const uint64_t pid; +}; + template class DebugLogger : public LoggerBase>{ using StreamType = std::vector; @@ -90,7 +103,7 @@ public: } void log(const std::exception& err, const uint8_t& lvl=0xFF) { - type_ptr->log(err.what(), lvl); + type_ptr->log(prepend_strblock(err.what(), " "), lvl); } template @@ -104,7 +117,6 @@ protected: private: LoggerType* type_ptr = static_cast(this); - }; class DefaultDebugLogger : public DebugLogger { diff --git a/engine/NBCore/StringUtils.hpp b/engine/NBCore/StringUtils.hpp new file mode 100644 index 0000000..a8cab98 --- /dev/null +++ b/engine/NBCore/StringUtils.hpp @@ -0,0 +1,142 @@ +#pragma once +#ifndef _NB_CORE_TYPES +#define _NB_CORE_TYPES + +#include +#include +#include + +#include "TypeTraits.hpp" + +namespace nb { + +#ifdef _NB_TARGET_WINDOWS + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; +#endif // _NB_TARGET_LINUX + +template +using StringConvertible = ValidConversion; + +template +using WStringConvertible = ValidConversion; + +template +constexpr bool StringConvertible_v = StringConvertible::value; + +template +constexpr bool WStringConvertible_v = WStringConvertible::value; + +template +using StringConvertible_to = typename StringConvertible::to; + +template +using WStringConvertible_to = typename WStringConvertible::to; + +template +using StringConvertible_from = typename StringConvertible::from; + +template +using WStringConvertible_from = typename WStringConvertible::from; + +template +std::enable_if_t, std::wstring> str_to_wstr(T in) { + std::string str(in); + std::wstring ret(str.begin(), str.end()); + return ret; +} + +template +std::enable_if_t, std::string> wstr_to_str(T in) { + std::wstring wstr(in); + std::size_t wstrlen = wstr.length(); + char* c_str= new char[wstrlen]; + std::wcstombs(c_str, wstr.c_str(), wstrlen); + std::string ret(c_str, wstrlen); + delete[] c_str; + return ret; +} + +template +void stream(Stream& s, Args&&... args); + +template +void stream(Stream& s, Args&&... args) { + (s << ... << args); +} + +template +void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } + +template +void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } + +template +ValidConversion_to find_and_replace( + A original, + B find, + C replace +) { + const T& find_t = T(find); + const T& replace_t = T(replace); + + T ret(original); + + std::size_t find_len = find_t.length(); + std::size_t replace_len = replace_t.length(); + std::size_t currpos = 0; + while(true) { + currpos = ret.find(find_t, currpos); + if (currpos == T::npos) { + break; + } + ret = ret.erase(currpos, find_len); + ret = ret.insert(currpos, replace_t); + currpos += replace_len; + } + return ret; +} + +template +StringConvertible_to indent_strblock( + A block, + B prepend, + C topIndent +) { + return std::string(topIndent) + find_and_replace( + std::string(block), + nb::NEWLINE, + nb::NEWLINE + std::string(prepend) + ); +} + +template +StringConvertible_to indent_strblock( + A block, + B prepend +) { + return indent_strblock(block, prepend, prepend); +} + +/* template +T swap_endian(const T& val) { + T ret; + const int size = sizeof(T); + auto retLoc = static_cast(&ret); + auto valLoc = static_cast(&val); + + for (int i = 0; i < size; ++i) { + memcpy(retLoc+i, valLoc+(size-i-1), 1); + } + return ret; +} */ + + +// using ByteVector = std::vector; + +} // namespace nb +#endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index 5277159..f92df9a 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -2,7 +2,9 @@ #ifndef _NB_TYPE_TRAITS #define _NB_TYPE_TRAITS +#include #include +#include namespace nb { @@ -37,11 +39,41 @@ template < > using is_detected = typename detail::detector::value; -/*template +template +struct ValidConversion; + +template +struct ValidConversion { + typedef std::conjunction< + std::is_constructible, std::is_constructible, std::conjunction...> + > value_type; + static constexpr bool value = value_type::value; + typedef std::enable_if_t to; + +}; + +template +struct ValidConversion { + typedef std::is_constructible value_type; + static constexpr bool value = value_type::value; + typedef std::enable_if_t to; + typedef std::enable_if_t from; +}; + +template +using ValidConversion_v = typename ValidConversion::value; + +template +using ValidConversion_to = typename ValidConversion::to; + +template +using ValidConversion_from = typename ValidConversion::from; + +template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} -template +template inline typename std::enable_if::type ForEach(std::tuple& tup, Func f) { f(N, std::get(tup)); @@ -99,7 +131,7 @@ struct PackIsSameType { template struct PackIsSameType { const bool value = std::is_base_of::value && PackIsSameType::value; -};*/ +}; } // namespace nb diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index 01d6dac..a8d47a5 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -2,80 +2,8 @@ #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES -#include -#include -#include - namespace nb { -#ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE = "\n"; - const std::wstring WNEWLINE = L"\n"; -#endif // _NB_TARGET_WINDOWS -#ifdef _NB_TARGET_LINUX - const std::string NEWLINE = "\n"; - const std::wstring WNEWLINE = L"\n"; -#endif // _NB_TARGET_LINUX - -template -std::enable_if_t, std::wstring> str_to_wstr(T in) { - std::string str(in); - std::wstring ret(str.begin(), str.end()); - return ret; -} - -template -std::enable_if_t, std::string> wstr_to_str(T in) { - std::wstring wstr(in); - std::size_t wstrlen = wstr.length(); - char* c_str= new char[wstrlen]; - std::wcstombs(c_str, wstr.c_str(), wstrlen); - std::string ret(c_str, wstrlen); - delete[] c_str; - return ret; -} - -template -void stream(Stream& s, Args&&... args); - -template -void stream(Stream& s, Args&&... args) { - (s << ... << args); -} - -template -void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } - -template -void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } - -template -T find_and_replace( - A original, - B find, - C replace -) { - const T& original_t = T(original); - const T& find_t = T(find); - const T& replace_t = T(replace); - - T ret = original_t; - - std::size_t find_len = find_t.length(); - std::size_t replace_len = replace_t.length(); - std::size_t currpos = 0; - while(true) { - currpos = ret.find(find_t, currpos); - if (currpos == T::npos) { - break; - } - ret = ret.erase(currpos, find_len); - ret = ret.insert(currpos, replace_t); - currpos += replace_len; - } - return ret; -} - /* template T swap_endian(const T& val) { T ret; diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 1deed87..042fdaf 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -10,6 +10,8 @@ static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); } + + static const bool LOGGER_RUNNING = RUN_LOGGER(logger); } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/src/StringUtils.cpp b/engine/NBCore/src/StringUtils.cpp new file mode 100644 index 0000000..44f97f5 --- /dev/null +++ b/engine/NBCore/src/StringUtils.cpp @@ -0,0 +1 @@ +#include "StringUtils.hpp" diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index 336d3b6..8b13789 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1,8 +1 @@ -#include -#include "Utils.hpp" -template<> -std::wstring nb::str_to_wstr(const std::string& in) { - std::wstring ret(in.begin(), in.end()); - return ret; -} diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 81187be..1e919aa 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -4,7 +4,6 @@ #include "Errors.hpp" #include -#include "Utils.hpp" using namespace nb; diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index e097788..24ca054 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -4,7 +4,7 @@ #include #include "TypeTraits.hpp" -#include "Utils.hpp" +#include "StringUtils.hpp" namespace nb { -- 2.43.0 From 0f62aecfa35c9fd1143df6a4f162ab4b0eb0f72b Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sun, 19 Apr 2026 19:19:47 -0500 Subject: [PATCH 07/18] Error logging almost working! --- CMakeLists.txt | 1 + engine/NBCore/CMakeLists.txt | 2 +- engine/NBCore/DataSink.hpp | 7 +++-- engine/NBCore/Errors.hpp | 7 +++-- engine/NBCore/Logger.hpp | 48 ++++++++++++++---------------- engine/NBCore/src/Logger.cpp | 14 +++++++++ engine/NBCore/tests/CMakeLists.txt | 8 +++++ engine/NBCore/tests/testLogger.cpp | 17 +++++++++++ 8 files changed, 73 insertions(+), 31 deletions(-) create mode 100644 engine/NBCore/tests/testLogger.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 65af2c9..9473a5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ endif() if (NB_LOGGING) message(STATUS "Building with automatic logging") add_compile_definitions(_NB_AUTOLOG) + add_compile_definitions(_NB_CODE_ERROR_LOCATIONS) endif() if (NB_TARGET_WINDOWS) diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index 9f67cd0..ee3a13b 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,6 +1,6 @@ toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp -# ./src/Logger.cpp + ./src/Logger.cpp ./src/Processes.cpp ./src/StringUtils.cpp ./src/Utils.cpp diff --git a/engine/NBCore/DataSink.hpp b/engine/NBCore/DataSink.hpp index 3aa0c50..d3c5d25 100644 --- a/engine/NBCore/DataSink.hpp +++ b/engine/NBCore/DataSink.hpp @@ -2,6 +2,7 @@ #ifndef _NB_DATASINK #define _NB_DATASINK +#include #include #include "ThreadSafeQueue.hpp" @@ -34,9 +35,9 @@ class BufferedDataProcessor : public DataSink { public: using Base::Base; - bool stop() noexcept { return type_ptr->stop(); } - bool run() { return type_ptr->run(); } - bool in(const DataType& val) { return type_ptr->in(val); } + virtual bool stop() noexcept override { return type_ptr->stop(); } + virtual bool run() override { return type_ptr->run(); } + virtual bool in(const DataType& val) override { return type_ptr->in(val); } protected: unsigned int count() const { diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index d36f749..35d94db 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -178,7 +178,7 @@ protected: ) noexcept : ErrorBase( 0, msg_, - nullptr, + static_cast(nullptr), line_, filename_ ) {} @@ -199,7 +199,7 @@ class Error : public ErrorBase { using Base = ErrorBase; public: template - Error(Args... T) : Base(T...) {} + Error(Args... args) : Base(args...) {} using Base::str; using Base::what; @@ -219,6 +219,9 @@ class Error : public ErrorBase> { public: using Base::Base; Error() : Base(0) {} + + template + Error(Args... args) : Base(args...) {} enum Codes : unsigned int { GENERAL, UNDEFINED, BADERRORCODE diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index 40919f6..2c332bf 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -8,22 +8,6 @@ #include #include -#ifndef THROW_WITH_INFO - #ifdef CODE_ERROR_LOCATIONS - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__) - #endif // CODE_ERROR_LOCATIONS -#endif // THROW_WITH_INFO - -#ifndef THROW - #ifdef LOGGING - #define THROW_WTIH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) - #endif // LOGGING -#endif // THROW - #include "DataSink.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" @@ -87,7 +71,7 @@ public: ~DebugLogger() { type_ptr->stop(); } - void log(const std::string& msg, const uint8_t& lvl=0xFF) { + void log(const std::string& msg, const uint8_t& lvl=0x00) { type_ptr->push(LogEvent{ std::chrono::system_clock::now(), lvl, @@ -98,12 +82,12 @@ public: } template - void log(char const(&msg) [N], const uint8_t& lvl=0xFF) { + void log(char const(&msg) [N], const uint8_t& lvl=0x00) { type_ptr->log(std::string(msg), lvl); } void log(const std::exception& err, const uint8_t& lvl=0xFF) { - type_ptr->log(prepend_strblock(err.what(), " "), lvl); + type_ptr->log(err.what(), lvl); } template @@ -139,17 +123,31 @@ public: protected: using Base::_ostream; - bool process(const LogEvent& msg) { - for (const auto os : this->_ostream) { - *os << msg.lvl << "\t|\t" << msg.msg << "\n"; - } - return true; - } + bool process(const LogEvent& msg); }; +#ifndef _NB_NO_LOGGER extern DefaultDebugLogger logger; +#endif // _NB_NO_LOGGER // Taking Charge of Adult ADHD by Russell Barkley } // namespace nb + +#ifndef CONSTRUCT_ERROR + #ifdef _NB_CODE_ERROR_LOCATIONS + #define CONSTRUCT_ERROR(type, ...) type(# __VA_ARGS__, __LINE__, __FILE__) + #else + #define CONSTRUCT_ERROR(type, ...) type(__VA_ARGS__) + #endif // _NB_CODE_ERROR_LOCATIONS +#endif // CONSTRUCT_ERROR + +#ifndef THROW + #ifdef _NB_AUTOLOG + #define THROW(type, ...) {auto x = CONSTRUCT_ERROR(type, ## __VA_ARGS__); nb::logger.error(x); throw x;} + #else + #define THROW(type, ...) throw CONSTRUCT_ERROR(type, __VA_ARGS__) + #endif // _NB_AUTOLOG +#endif // THROW + #endif // _NB_LOGGER \ No newline at end of file diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 042fdaf..b9353a4 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -1,10 +1,24 @@ #include #include "Logger.hpp" +#include "StringUtils.hpp" namespace nb { +#ifndef _NB_NO_LOGGER nb::DefaultDebugLogger logger(std::cout); +#endif // _NB_NO_LOGGER + +bool nb::DefaultDebugLogger::process(const LogEvent& msg) { + for (const auto os : this->_ostream) { + *os << indent_strblock( + msg.msg, + std::string(10, ' '), + "[ "+std::to_string(msg.lvl)+" ] : " + ) << nb::NEWLINE; + } + return true; +} static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); diff --git a/engine/NBCore/tests/CMakeLists.txt b/engine/NBCore/tests/CMakeLists.txt index 02c31c7..34476ff 100644 --- a/engine/NBCore/tests/CMakeLists.txt +++ b/engine/NBCore/tests/CMakeLists.txt @@ -12,5 +12,13 @@ if (NB_BUILD_TESTS) NBCore GTest::gtest_main ) + + add_executable(LoggerTest + ./testLogger.cpp + ) + target_link_libraries(LoggerTest + NBCore + ) + gtest_discover_tests(TestCore) endif() \ No newline at end of file diff --git a/engine/NBCore/tests/testLogger.cpp b/engine/NBCore/tests/testLogger.cpp new file mode 100644 index 0000000..da6fb99 --- /dev/null +++ b/engine/NBCore/tests/testLogger.cpp @@ -0,0 +1,17 @@ +#include + +#include "Errors.hpp" +#include "Logger.hpp" + + + +int main() { + nb::logger.log("Whoop!"); + try { + THROW(nb::Error, "Hiii!"); + } catch (nb::Error e){ + nb::logger.log("Winner winner chicken dinner!"); + } + + return 0; +} \ No newline at end of file -- 2.43.0 From 58121bdf2818c113af3441a11557663c15e0b603 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sat, 2 May 2026 01:50:53 -0500 Subject: [PATCH 08/18] Got logging and errors basically all working the way I want --- engine/NBCore/Errors.hpp | 331 ++++++++++++++++------------- engine/NBCore/Logger.hpp | 168 ++++++++++++--- engine/NBCore/StringUtils.hpp | 117 +++------- engine/NBCore/TypeTraits.hpp | 18 ++ engine/NBCore/src/Errors.cpp | 7 +- engine/NBCore/src/Logger.cpp | 16 +- engine/NBCore/src/StringUtils.cpp | 28 +++ engine/NBCore/tests/testErrors.cpp | 2 +- engine/NBCore/tests/testLogger.cpp | 35 ++- engine/NBCore/tests/testUtils.cpp | 34 +-- 10 files changed, 465 insertions(+), 291 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 35d94db..2e38434 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "TypeTraits.hpp" #include @@ -15,103 +14,87 @@ namespace nb { typedef std::unordered_map ErrorCodeMap; +template +constexpr bool IsValidException_v = std::is_base_of_v; template -using has_type = decltype(T::type); +using IsValidException = std::enable_if_t, bool>; -template +template class ErrorBase; +template +class Error; + +template +constexpr bool IsValidNBError_v = std::is_base_of_v, T>; +template +using IsValidNBError = std::enable_if_t, bool>; + + template<> -class ErrorBase : public std::exception { +class ErrorBase { public: const unsigned int code; const std::string msg; - const std::shared_ptr trace; + const std::string type; + const std::shared_ptr trace; const bool traceIsNBError; - virtual inline std::string str() const noexcept = 0; - - virtual const char* what() const noexcept override final { - const std::string& ret = str(); - return ret.c_str(); - } - + virtual std::string what() const noexcept = 0; + virtual std::shared_ptr make_shared() const noexcept = 0; + protected: - template < - typename TraceType = std::exception, - std::enable_if_t, bool> = true - > + template + ErrorBase(const ErrorBase& err) : ErrorBase(std::move(err)) {} + + template + ErrorBase(ErrorBase&& err) : ErrorBase( + err.code, + err.msg, + err.type, + (err.traceIsNBError) + ? static_cast(err.trace.get()) + : static_cast(err.trace.get()) + ) {} + ErrorBase( - const unsigned int& code_, - const std::string& msg_, - const std::shared_ptr trace_, - const unsigned int& line_, - std::string filename_ + unsigned int code_, + std::string msg_, + std::string type_, + const std::exception* trace_ ) noexcept : code(code_), msg(msg_), - trace{std::dynamic_pointer_cast(trace_)}, - traceIsNBError( trace_ ? is_detected::value : false) - { - static_assert(std::is_base_of::value, - "`trace_` must be a pointer to a child object of std::exception." - ); - } + type(type_), + trace{ trace_ ? + std::static_pointer_cast( + std::make_shared>(*trace_)) + : nullptr, + }, + traceIsNBError(false) + {} + + template, bool> = true> + ErrorBase( + unsigned int code_, + std::string msg_, + std::string type_, + const T* trace_ + ) noexcept : + code(code_), + msg(msg_), + type(type_), + trace{trace_ ? trace_->make_shared() : nullptr}, + traceIsNBError(true) + {} }; + template class ErrorBase : public ErrorBase { +private: using Base = ErrorBase; -public: - ErrorBase(const ErrorBase&) = default; - ErrorBase& operator=(const ErrorBase&) = delete; - - virtual inline std::string str() const noexcept override { - std::string ret = msg + nb::NEWLINE; - if (trace) { - const std::string tabover = " "; - std::string trace_msg; - if (traceIsNBError) { - trace_msg = std::static_pointer_cast(trace)->str(); - trace_msg = std::string(std::string_view(trace_msg).substr( - 0, trace_msg.length()-nb::NEWLINE.length() - )); - } else { - trace_msg = std::string(trace->what()); - } - ret += indent_strblock(trace_msg, tabover, tabover+"Trace: ")+nb::NEWLINE; - } - return ret; - } - - static const std::string type; - static const ErrorCodeMap ErrorMessages; - - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - -protected: - using Base::Base; - - template < - typename TraceType = std::exception, - std::enable_if_t, bool> = true - > - ErrorBase( - const unsigned int code_, - std::string msg_, - const TraceType* trace_=nullptr, - unsigned int line_=0, - std::string filename_="" - ) : Base( - code_, - msg_, - trace_ ? std::make_shared(*trace_) : nullptr, - line_, - filename_ - ) { + void inline check_asserts() { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " "a class member." @@ -125,83 +108,117 @@ protected: ); } - template < - typename TraceType, - std::enable_if_t, bool> = true - > - ErrorBase( - const unsigned int& code_, - const TraceType& trace_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - code_, - ErrorType::ErrorMessages.at(code_), - &trace_, - line_, - filename_ - ) {} +public: + template + ErrorBase(const ErrorBase& cpy) : Base(cpy) { check_asserts(); } - template < - typename TraceType, - std::enable_if_t, bool> = true - > + virtual std::shared_ptr make_shared() const noexcept override { + return std::static_pointer_cast( + std::make_shared(*this) + ); + } + + virtual std::string what() const noexcept override { + std::string ret = msg; + if (trace) { + std::string trace_msg; + if (traceIsNBError) { + trace_msg = std::static_pointer_cast(trace)->what(); + } else { + trace_msg = std::string(std::static_pointer_cast(trace)->what()); + } + ret += nb::NEWLINE + indent_strblock( + trace_msg, + nb::TABOVER, + nb::TABOVER+"Trace: " + ); + } + return ret; + } + + static const std::string type; + static const ErrorCodeMap ErrorMessages; + + using Base::code; + using Base::msg; + using Base::trace; + using Base::traceIsNBError; + + friend ErrorType; + friend Error; + +protected: + using Base::Base; + + template ErrorBase( - const std::string& msg_, - const TraceType& trace_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - 0, + unsigned int code_, + std::string msg_, + std::string type_, + const T* trace_ + ) : Base( + code_, msg_, - &trace_, - line_, - filename_ - ) {} - - ErrorBase( - const unsigned int& code_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - code_, - ErrorType::ErrorMessages.at(code_), - static_cast(nullptr), - line_, - filename_ - ) {} - - ErrorBase( - const std::string& msg_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - 0, - msg_, - static_cast(nullptr), - line_, - filename_ - ) {} + type_, + trace_ + ) { check_asserts(); } }; template const std::string ErrorBase::type = ErrorType::type; template const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; -template -class Error; - -template<> -class Error; template class Error : public ErrorBase { using Base = ErrorBase; -public: - template - Error(Args... args) : Base(args...) {} +public: + template + Error( + unsigned int code_, + const T& trace_ + ) noexcept : Base( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + &trace_ + ) {} + + template + Error( + std::string msg_, + const ErrorBase& trace_ + ) noexcept : Base( + 0, + msg_, + ErrorType::type, + &trace_ + ) {} + + Error( + std::string msg_, + const std::exception& trace_ + ) noexcept : Base( + 0, + msg_, + ErrorType::type, + &trace_ + ) {} + + Error(unsigned int code_) noexcept : Base( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + NULLPTR + ) {} + + Error(std::string msg_) noexcept : Base( + 0, + msg_, + ErrorType::type, + NULLPTR + ) {} - using Base::str; using Base::what; using Base::code; using Base::msg; @@ -210,24 +227,43 @@ public: using Base::type; using Base::ErrorMessages; - friend ErrorBase; +protected: + using Base::Base; + }; + template<> class Error : public ErrorBase> { using Base = ErrorBase>; public: using Base::Base; - Error() : Base(0) {} - template - Error(Args... args) : Base(args...) {} + Error(unsigned int code_=1) noexcept : Base( + code_, + ErrorMessages.at(code_), + type, + NULLPTR + ) {} + + Error(const std::exception& err) : Base( + Codes::STANDARD, + std::string(err.what()), + "std::exception", + nullptr + ) {} + + Error(std::string msg_) noexcept : Base( + Codes::UNDEFINED, + msg_, + type, + NULLPTR + ) {} enum Codes : unsigned int { - GENERAL, UNDEFINED, BADERRORCODE + STANDARD, UNDEFINED }; - using Base::str; using Base::what; using Base::code; @@ -238,6 +274,7 @@ public: static const ErrorCodeMap ErrorMessages; }; + } // namespace nb #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index 2c332bf..e0f1f19 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -9,6 +9,7 @@ #include #include "DataSink.hpp" +#include "Errors.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" @@ -31,24 +32,21 @@ class LoggerBase using Base = MultithreadedDataProcessor; public: bool run() override { - if (!type_ptr->isRunning()) { + if (!static_cast(this)->isRunning()) { this->_running = true; this->_runningThread = std::make_shared([&]{ - while(type_ptr->isRunning()) { - type_ptr->flush(); + while(static_cast(this)->isRunning()) { + static_cast(this)->flush(); } - type_ptr->flush(); + static_cast(this)->flush(); }); } - return type_ptr->isRunning(); + return static_cast(this)->isRunning(); } protected: LoggerBase() = default; StreamType _ostream; - -private: - LoggerType* type_ptr = static_cast(this); }; struct LogEvent{ @@ -57,6 +55,8 @@ struct LogEvent{ const std::string msg; const std::thread::id tid; const uint64_t pid; + const std::string file=""; + const unsigned int line=0; }; template @@ -69,38 +69,73 @@ public: template DebugLogger(ST&... streams) : _ostream(nb::RefPackToPtrVec(streams...).vec) {} - ~DebugLogger() { type_ptr->stop(); } + ~DebugLogger() { static_cast(this)->stop(); } - void log(const std::string& msg, const uint8_t& lvl=0x00) { - type_ptr->push(LogEvent{ + void log( + std::string msg, + uint8_t lvl=0x00, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->push(LogEvent{ std::chrono::system_clock::now(), lvl, msg, std::this_thread::get_id(), GetPID(), + file, + line }); } template - void log(char const(&msg) [N], const uint8_t& lvl=0x00) { - type_ptr->log(std::string(msg), lvl); + void log( + char const(&msg) [N], + uint8_t lvl=0x00, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->log(std::string(msg), lvl, file, line); } - void log(const std::exception& err, const uint8_t& lvl=0xFF) { - type_ptr->log(err.what(), lvl); + template + void log( + const ErrorBase& err, + uint8_t lvl=0xFF, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->log(err.what(), lvl, file, line); + } + + template + std::enable_if_t, void> log( + const T& err, + uint8_t lvl=0xFF, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->log(std::string(err.what()), lvl, file, line); } template - void warn(const U& val, const uint8_t& lvl=0x01) { type_ptr->log(val, lvl); } + void warn( + U val, + uint8_t lvl=0x01, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->log(val, lvl, file, line); } template - void error(const U& val) { type_ptr->log(val, 0xFF); } + void error( + U val, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->log(val, 0xFF, file, line); } protected: std::vector _ostream; -private: - LoggerType* type_ptr = static_cast(this); }; class DefaultDebugLogger : public DebugLogger { @@ -132,22 +167,103 @@ extern DefaultDebugLogger logger; // Taking Charge of Adult ADHD by Russell Barkley +/* template +struct NB_DEFAULT_LOGGER_THROW; + +template<> +struct NB_DEFAULT_LOGGER_THROW { + template + NB_DEFAULT_LOGGER_THROW(T arg) { + #ifdef _NB_AUTOLOG + logger.error(arg); + #endif // _NB_AUTLOG + throw arg; + } +}; + +template +struct NB_DEFAULT_LOGGER_THROW { + template + NB_DEFAULT_LOGGER_THROW(Args&&... args) { + std::shared_ptr error_ptr; + #ifdef _NB_AUTOLOG + #ifdef _NB_CODE_ERROR_LOCATIONS + error_ptr = std::make_shared(args..., __LINE__, __FILE__); + #else + error_ptr = std::make_shared(args...); + #endif // _NB_CODE_ERROR_LOCATIONS + logger.error(*error_ptr); + #endif // _NB_AUTLOG + throw *error_ptr; + } +}; */ + +/* template +void NB_DEFAULT_LOGGER_THROW(Args&& ... args) { + std::shared_ptr error_ptr; + #ifdef _NB_AUTOLOG + #ifdef _NB_CODE_ERROR_LOCATIONS + error_ptr = std::make_shared(args..., __LINE__, __FILE__); + #else + error_ptr = std::make_shared(args...); + #endif // _NB_CODE_ERROR_LOCATIONS + logger.error(*error_ptr); + #endif // _NB_AUTLOG + throw *error_ptr; +} + +template +void NB_DEFAULT_LOGGER_THROW(const Arg& arg) { + #ifdef _NB_AUTOLOG + logger.error(arg); + #endif // _NB_AUTLOG + throw arg; +} */ + +template +void NB_DEFAULT_LOGGER_THROW(const T& err, std::string file="", unsigned int line = 0) { + #ifdef _NB_AUTOLOG + if (file.empty()) { + logger.error(err); + } else { + logger.error(err, file, line); + } + #endif // _NB_AUTLOG + throw err; +} + } // namespace nb -#ifndef CONSTRUCT_ERROR +#ifdef _NB_AUTOLOG #ifdef _NB_CODE_ERROR_LOCATIONS - #define CONSTRUCT_ERROR(type, ...) type(# __VA_ARGS__, __LINE__, __FILE__) + #ifndef LOG + #define LOG(args...) nb::logger.log(args, __FILE__, __LINE__) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__) + #endif // ERROR #else - #define CONSTRUCT_ERROR(type, ...) type(__VA_ARGS__) + #ifndef LOG + #define LOG(args...) nb::logger.log(args) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args) + #endif // ERROR #endif // _NB_CODE_ERROR_LOCATIONS -#endif // CONSTRUCT_ERROR +#endif // _NB_AUTOLOG #ifndef THROW #ifdef _NB_AUTOLOG - #define THROW(type, ...) {auto x = CONSTRUCT_ERROR(type, ## __VA_ARGS__); nb::logger.error(x); throw x;} + #define THROW(args...) ERROR(args); throw args #else - #define THROW(type, ...) throw CONSTRUCT_ERROR(type, __VA_ARGS__) - #endif // _NB_AUTOLOG + #define THROW(args...) throw args + #endif // _NB_CODE_ERROR_LOCATIONS #endif // THROW #endif // _NB_LOGGER \ No newline at end of file diff --git a/engine/NBCore/StringUtils.hpp b/engine/NBCore/StringUtils.hpp index a8cab98..9b709e1 100644 --- a/engine/NBCore/StringUtils.hpp +++ b/engine/NBCore/StringUtils.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "TypeTraits.hpp" @@ -19,53 +19,17 @@ namespace nb { const std::wstring WNEWLINE = L"\n"; #endif // _NB_TARGET_LINUX -template -using StringConvertible = ValidConversion; +const std::string TABOVER = " "; -template -using WStringConvertible = ValidConversion; +// std::wstring str_to_wstr(std::string in); -template -constexpr bool StringConvertible_v = StringConvertible::value; - -template -constexpr bool WStringConvertible_v = WStringConvertible::value; - -template -using StringConvertible_to = typename StringConvertible::to; - -template -using WStringConvertible_to = typename WStringConvertible::to; - -template -using StringConvertible_from = typename StringConvertible::from; - -template -using WStringConvertible_from = typename WStringConvertible::from; - -template -std::enable_if_t, std::wstring> str_to_wstr(T in) { - std::string str(in); - std::wstring ret(str.begin(), str.end()); - return ret; -} - -template -std::enable_if_t, std::string> wstr_to_str(T in) { - std::wstring wstr(in); - std::size_t wstrlen = wstr.length(); - char* c_str= new char[wstrlen]; - std::wcstombs(c_str, wstr.c_str(), wstrlen); - std::string ret(c_str, wstrlen); - delete[] c_str; - return ret; -} +// std::string wstr_to_str(std::wstring in); template -void stream(Stream& s, Args&&... args); +void stream(const Stream& s, Args&&... args); template -void stream(Stream& s, Args&&... args) { +void stream(const Stream& s, Args&&... args) { (s << ... << args); } @@ -75,68 +39,41 @@ void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } template void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } -template -ValidConversion_to find_and_replace( - A original, - B find, - C replace +template +std::basic_string find_and_replace( + ExplicitType_t> original, + ExplicitType_t> find, + ExplicitType_t> replace ) { - const T& find_t = T(find); - const T& replace_t = T(replace); + using StringType = std::basic_string; - T ret(original); + StringType ret(original); - std::size_t find_len = find_t.length(); - std::size_t replace_len = replace_t.length(); + std::size_t find_len = find.length(); + std::size_t replace_len = replace.length(); std::size_t currpos = 0; while(true) { - currpos = ret.find(find_t, currpos); - if (currpos == T::npos) { + currpos = ret.find(find, currpos); + if (currpos == StringType::npos) { break; } ret = ret.erase(currpos, find_len); - ret = ret.insert(currpos, replace_t); + ret = ret.insert(currpos, replace); currpos += replace_len; } return ret; } -template -StringConvertible_to indent_strblock( - A block, - B prepend, - C topIndent -) { - return std::string(topIndent) + find_and_replace( - std::string(block), - nb::NEWLINE, - nb::NEWLINE + std::string(prepend) - ); -} +std::string indent_strblock( + std::string block, + std::string prepend, + std::string topIndent +); -template -StringConvertible_to indent_strblock( - A block, - B prepend -) { - return indent_strblock(block, prepend, prepend); -} - -/* template -T swap_endian(const T& val) { - T ret; - const int size = sizeof(T); - auto retLoc = static_cast(&ret); - auto valLoc = static_cast(&val); - - for (int i = 0; i < size; ++i) { - memcpy(retLoc+i, valLoc+(size-i-1), 1); - } - return ret; -} */ - - -// using ByteVector = std::vector; +std::string indent_strblock( + std::string block, + std::string prepend +); } // namespace nb #endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index f92df9a..fb990fe 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -69,6 +69,24 @@ using ValidConversion_to = typename ValidConversion::to; template using ValidConversion_from = typename ValidConversion::from; +template +struct ExplicitType { using type=T; }; + +template +using ExplicitType_t = typename ExplicitType::type; + +template +T* NULLPTR = static_cast(nullptr); + +template +struct RunAndOutput { + using type = T; + T value; + RunAndOutput(Func func, T val) : value(val) { + func(); + } +}; + template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp index 43b6227..e5b22fa 100644 --- a/engine/NBCore/src/Errors.cpp +++ b/engine/NBCore/src/Errors.cpp @@ -3,12 +3,11 @@ namespace nb { -const std::string Error::type = "nb::Error"; +const std::string Error<>::type = "nb::Error"; const ErrorCodeMap Error::ErrorMessages = { - {Error::Codes::GENERAL, "General std::exception."}, - {Error::Codes::UNDEFINED, "Undefined / general error."}, - {Error::Codes::BADERRORCODE, "Unrecognized error code."} + {Error::Codes::STANDARD, "std::exception"}, + {Error::Codes::UNDEFINED, "Error"} }; } diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index b9353a4..795136d 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -10,11 +10,21 @@ nb::DefaultDebugLogger logger(std::cout); #endif // _NB_NO_LOGGER bool nb::DefaultDebugLogger::process(const LogEvent& msg) { + constexpr size_t level_field_width = 3; + constexpr size_t msg_prompt_length = level_field_width+6; for (const auto os : this->_ostream) { + *os << "["; + os->width(level_field_width); + (*os << std::to_string(msg.lvl)).width(level_field_width); + *os << "] :: "; + std::string fileloc=""; + if (!msg.file.empty()) { + fileloc += "(" + msg.file + ":" + std::to_string(msg.line) + ") - "; + } *os << indent_strblock( - msg.msg, - std::string(10, ' '), - "[ "+std::to_string(msg.lvl)+" ] : " + fileloc + msg.msg, + std::string(15 - msg_prompt_length, ' '), + "" ) << nb::NEWLINE; } return true; diff --git a/engine/NBCore/src/StringUtils.cpp b/engine/NBCore/src/StringUtils.cpp index 44f97f5..1946c3c 100644 --- a/engine/NBCore/src/StringUtils.cpp +++ b/engine/NBCore/src/StringUtils.cpp @@ -1 +1,29 @@ #include "StringUtils.hpp" + +/* std::string nb::wstr_to_str(std::wstring in) { + std::size_t wstrlen = in.length(); + char* c_str= new char[wstrlen]; + std::wcstombs(c_str, in.c_str(), wstrlen); + std::string ret(c_str, wstrlen); + delete[] c_str; + return ret; +} */ + +std::string nb::indent_strblock( + std::string block, + std::string prepend, + std::string topIndent +) { + return topIndent + nb::find_and_replace( + block, + nb::NEWLINE, + nb::NEWLINE + prepend + ); +} + +std::string nb::indent_strblock( + std::string block, + std::string prepend +) { + return nb::indent_strblock(block, prepend, prepend); +} diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 1e919aa..0c7be49 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -35,5 +35,5 @@ const ErrorCodeMap TestError::ErrorMessages{ TEST(ErrorTest, Test) { auto err = TestError(0, TestError(1, TestError(2, TestError(3, TestError(2))))); - ASSERT_STREQ(err.what(), "Hey!\n Trace: How\n Trace: You\n Trace: Doin\n Trace: You\n"); + ASSERT_STREQ(err.what().c_str(), "Hey!\n Trace: How\n Trace: You\n Trace: Doin\n Trace: You"); } \ No newline at end of file diff --git a/engine/NBCore/tests/testLogger.cpp b/engine/NBCore/tests/testLogger.cpp index da6fb99..451a01f 100644 --- a/engine/NBCore/tests/testLogger.cpp +++ b/engine/NBCore/tests/testLogger.cpp @@ -3,14 +3,43 @@ #include "Errors.hpp" #include "Logger.hpp" +class TestError : public nb::Error { + using Base = Error; +public: + using Base::Base; + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; + enum Codes : unsigned int { + A, B, C, D + }; + + static const std::string type; + static const nb::ErrorCodeMap ErrorMessages; +}; + +const std::string TestError::type="TestError"; +const nb::ErrorCodeMap TestError::ErrorMessages{ + {TestError::Codes::A, "Hey!"}, + {TestError::Codes::B, "How"}, + {TestError::Codes::C, "You"}, + {TestError::Codes::D, "Doin"} +}; int main() { nb::logger.log("Whoop!"); try { - THROW(nb::Error, "Hiii!"); - } catch (nb::Error e){ - nb::logger.log("Winner winner chicken dinner!"); + THROW(nb::Error(1)); + } catch (nb::Error<> e){ + nb::logger.log("nb::Error was thrown!"); + } + + try { + THROW(std::exception()); + } catch (std::exception e){ + nb::logger.log("std::exception was thrown!"); } return 0; diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index 24ca054..a726369 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -43,38 +43,38 @@ TEST(UtilsTest, TestFindAndReplace) { TEST(UtilsTest, TestFindAndReplaceWstr) { ASSERT_STREQ( - find_and_replace(L"Jeff", L"e", L"efe").c_str(), + find_and_replace(L"Jeff", L"e", L"efe").c_str(), L"Jefeff" ); - std::wstring tmp = find_and_replace(L"Naif", L"a", L"afa"); + std::wstring tmp = find_and_replace(L"Naif", L"a", L"afa"); ASSERT_STREQ( - find_and_replace(tmp, L"i", L"ifi").c_str(), + find_and_replace(tmp, L"i", L"ifi").c_str(), L"Nafaifif" ); - tmp = find_and_replace(L"aeiou", L"a", L"afa"); - tmp = find_and_replace(tmp, L"e", L"efe"); - tmp = find_and_replace(tmp, L"i", L"ifi"); - tmp = find_and_replace(tmp, L"o", L"ofo"); - tmp = find_and_replace(tmp, L"u", L"ufu"); + tmp = find_and_replace(L"aeiou", L"a", L"afa"); + tmp = find_and_replace(tmp, L"e", L"efe"); + tmp = find_and_replace(tmp, L"i", L"ifi"); + tmp = find_and_replace(tmp, L"o", L"ofo"); + tmp = find_and_replace(tmp, L"u", L"ufu"); ASSERT_STREQ( tmp.c_str(), L"afaefeifiofoufu" ); - tmp = find_and_replace(tmp, L"afa", L"a"); - tmp = find_and_replace(tmp, L"efe", L"e"); - tmp = find_and_replace(tmp, L"ifi", L"i"); - tmp = find_and_replace(tmp, L"ofo", L"o"); - tmp = find_and_replace(tmp, L"ufu", L"u"); + tmp = find_and_replace(tmp, L"afa", L"a"); + tmp = find_and_replace(tmp, L"efe", L"e"); + tmp = find_and_replace(tmp, L"ifi", L"i"); + tmp = find_and_replace(tmp, L"ofo", L"o"); + tmp = find_and_replace(tmp, L"ufu", L"u"); ASSERT_STREQ( tmp.c_str(), L"aeiou" ); } -TEST(UtilsTest, TestWstrToStr) { +/* TEST(UtilsTest, TestWstrToStr) { ASSERT_STREQ( nb::wstr_to_str(L"Hi!").c_str(), "Hi!" @@ -91,9 +91,9 @@ TEST(UtilsTest, TestWstrToStr) { nb::wstr_to_str(L"Naif\ttalks\r\ra\t\nlot").c_str(), "Naif\ttalks\r\ra\t\nlot" ); -} +} */ -TEST(UtilsTest, TestStrToWstr) { +/* TEST(UtilsTest, TestStrToWstr) { ASSERT_STREQ( nb::str_to_wstr("Hi!").c_str(), L"Hi!" @@ -110,7 +110,7 @@ TEST(UtilsTest, TestStrToWstr) { nb::str_to_wstr("Naif\ttalks\r\ra\t\nlot").c_str(), L"Naif\ttalks\r\ra\t\nlot" ); -} +} */ struct A { bool x(); }; struct B { bool y(); }; -- 2.43.0 From 13ef940b2de76ac6f6d7bd5d587f1a60d9003cf0 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sat, 2 May 2026 03:37:06 -0500 Subject: [PATCH 09/18] Formatting tweaks --- engine/NBCore/src/Logger.cpp | 9 ++++----- engine/NBCore/tests/testLogger.cpp | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 795136d..f2d0c8e 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -10,20 +10,19 @@ nb::DefaultDebugLogger logger(std::cout); #endif // _NB_NO_LOGGER bool nb::DefaultDebugLogger::process(const LogEvent& msg) { - constexpr size_t level_field_width = 3; - constexpr size_t msg_prompt_length = level_field_width+6; + constexpr size_t level_field_width = 5; + constexpr size_t msg_prompt_length = level_field_width+7; for (const auto os : this->_ostream) { *os << "["; os->width(level_field_width); - (*os << std::to_string(msg.lvl)).width(level_field_width); - *os << "] :: "; + *os << std::to_string(msg.lvl) << "] :: "; std::string fileloc=""; if (!msg.file.empty()) { fileloc += "(" + msg.file + ":" + std::to_string(msg.line) + ") - "; } *os << indent_strblock( fileloc + msg.msg, - std::string(15 - msg_prompt_length, ' '), + std::string(20 - msg_prompt_length, ' '), "" ) << nb::NEWLINE; } diff --git a/engine/NBCore/tests/testLogger.cpp b/engine/NBCore/tests/testLogger.cpp index 451a01f..27da8da 100644 --- a/engine/NBCore/tests/testLogger.cpp +++ b/engine/NBCore/tests/testLogger.cpp @@ -31,8 +31,8 @@ const nb::ErrorCodeMap TestError::ErrorMessages{ int main() { nb::logger.log("Whoop!"); try { - THROW(nb::Error(1)); - } catch (nb::Error<> e){ + THROW(TestError(0, TestError(1, TestError(2, TestError(3, TestError(2)))))); + } catch (TestError e){ nb::logger.log("nb::Error was thrown!"); } @@ -41,6 +41,6 @@ int main() { } catch (std::exception e){ nb::logger.log("std::exception was thrown!"); } - + ERROR("hello there!"); return 0; } \ No newline at end of file -- 2.43.0 From cff7164d27b9a855bd36a6fc351051ade2a916ca Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Thu, 11 Jun 2026 04:23:29 -0500 Subject: [PATCH 10/18] Mild cleanup --- engine/NBCore/Errors.hpp | 38 +++++++++++- engine/NBCore/Logger.hpp | 106 +++----------------------------- engine/NBCore/Processes.hpp | 2 + engine/NBCore/StringUtils.hpp | 6 +- engine/NBCore/Utils.hpp | 78 +++++++++++++++++++---- engine/NBCore/src/Logger.cpp | 2 - engine/NBCore/src/Processes.cpp | 9 ++- engine/NBCore/src/Utils.cpp | 26 ++++++++ 8 files changed, 148 insertions(+), 119 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 2e38434..89cc13b 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -6,9 +6,11 @@ #include #include #include -#include "TypeTraits.hpp" #include + +#include "Logger.hpp" #include "StringUtils.hpp" +#include "TypeTraits.hpp" namespace nb { @@ -273,8 +275,38 @@ public: static const std::string type; static const ErrorCodeMap ErrorMessages; }; - - } // namespace nb +#ifdef _NB_AUTOLOG + #ifdef _NB_CODE_ERROR_LOCATIONS + #ifndef LOG + #define LOG(args...) nb::logger.log(args, __FILE__, __LINE__) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__) + #endif // ERROR + #else + #ifndef LOG + #define LOG(args...) nb::logger.log(args) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args) + #endif // ERROR + #endif // _NB_CODE_ERROR_LOCATIONS +#endif // _NB_AUTOLOG + +#ifndef THROW + #ifdef _NB_AUTOLOG + #define THROW(args...) ERROR(args); throw args + #else + #define THROW(args...) throw args + #endif // _NB_CODE_ERROR_LOCATIONS +#endif // THROW + #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index e0f1f19..2d64198 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -9,13 +9,15 @@ #include #include "DataSink.hpp" -#include "Errors.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" namespace nb { +template +class ErrorBase; + typedef std::chrono::time_point< std::chrono::system_clock, std::chrono::nanoseconds @@ -131,7 +133,10 @@ public: U val, std::string file="", unsigned int line=0 - ) { static_cast(this)->log(val, 0xFF, file, line); } + ) { + static_cast(this)->log(val, 0xFF, file, line); + static_cast(this)->flush(); + } protected: std::vector _ostream; @@ -167,103 +172,6 @@ extern DefaultDebugLogger logger; // Taking Charge of Adult ADHD by Russell Barkley -/* template -struct NB_DEFAULT_LOGGER_THROW; - -template<> -struct NB_DEFAULT_LOGGER_THROW { - template - NB_DEFAULT_LOGGER_THROW(T arg) { - #ifdef _NB_AUTOLOG - logger.error(arg); - #endif // _NB_AUTLOG - throw arg; - } -}; - -template -struct NB_DEFAULT_LOGGER_THROW { - template - NB_DEFAULT_LOGGER_THROW(Args&&... args) { - std::shared_ptr error_ptr; - #ifdef _NB_AUTOLOG - #ifdef _NB_CODE_ERROR_LOCATIONS - error_ptr = std::make_shared(args..., __LINE__, __FILE__); - #else - error_ptr = std::make_shared(args...); - #endif // _NB_CODE_ERROR_LOCATIONS - logger.error(*error_ptr); - #endif // _NB_AUTLOG - throw *error_ptr; - } -}; */ - -/* template -void NB_DEFAULT_LOGGER_THROW(Args&& ... args) { - std::shared_ptr error_ptr; - #ifdef _NB_AUTOLOG - #ifdef _NB_CODE_ERROR_LOCATIONS - error_ptr = std::make_shared(args..., __LINE__, __FILE__); - #else - error_ptr = std::make_shared(args...); - #endif // _NB_CODE_ERROR_LOCATIONS - logger.error(*error_ptr); - #endif // _NB_AUTLOG - throw *error_ptr; -} - -template -void NB_DEFAULT_LOGGER_THROW(const Arg& arg) { - #ifdef _NB_AUTOLOG - logger.error(arg); - #endif // _NB_AUTLOG - throw arg; -} */ - -template -void NB_DEFAULT_LOGGER_THROW(const T& err, std::string file="", unsigned int line = 0) { - #ifdef _NB_AUTOLOG - if (file.empty()) { - logger.error(err); - } else { - logger.error(err, file, line); - } - #endif // _NB_AUTLOG - throw err; -} - } // namespace nb -#ifdef _NB_AUTOLOG - #ifdef _NB_CODE_ERROR_LOCATIONS - #ifndef LOG - #define LOG(args...) nb::logger.log(args, __FILE__, __LINE__) - #endif // LOG - #ifndef WARN - #define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__) - #endif // WARN - #ifndef ERROR - #define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__) - #endif // ERROR - #else - #ifndef LOG - #define LOG(args...) nb::logger.log(args) - #endif // LOG - #ifndef WARN - #define WARN(args...) nb::logger.warn(args) - #endif // WARN - #ifndef ERROR - #define ERROR(args...) nb::logger.error(args) - #endif // ERROR - #endif // _NB_CODE_ERROR_LOCATIONS -#endif // _NB_AUTOLOG - -#ifndef THROW - #ifdef _NB_AUTOLOG - #define THROW(args...) ERROR(args); throw args - #else - #define THROW(args...) throw args - #endif // _NB_CODE_ERROR_LOCATIONS -#endif // THROW - #endif // _NB_LOGGER \ No newline at end of file diff --git a/engine/NBCore/Processes.hpp b/engine/NBCore/Processes.hpp index 87ee029..87c16ee 100644 --- a/engine/NBCore/Processes.hpp +++ b/engine/NBCore/Processes.hpp @@ -7,6 +7,8 @@ namespace nb { uint64_t GetPID(); +uint64_t getTID(); + } // namespace nb diff --git a/engine/NBCore/StringUtils.hpp b/engine/NBCore/StringUtils.hpp index 9b709e1..b8d9778 100644 --- a/engine/NBCore/StringUtils.hpp +++ b/engine/NBCore/StringUtils.hpp @@ -1,6 +1,6 @@ #pragma once -#ifndef _NB_CORE_TYPES -#define _NB_CORE_TYPES +#ifndef _NB_STRING_UTILS +#define _NB_STRING_UTILS #include #include @@ -76,4 +76,4 @@ std::string indent_strblock( ); } // namespace nb -#endif // _NB_CORE_TYPES \ No newline at end of file +#endif // _NB_STRING_UTILS \ No newline at end of file diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index a8d47a5..b7a477d 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -2,23 +2,79 @@ #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES +#include +#include + +#include "Errors.hpp" + namespace nb { -/* template -T swap_endian(const T& val) { - T ret; - const int size = sizeof(T); - auto retLoc = static_cast(&ret); - auto valLoc = static_cast(&val); +using ByteVector = std::vector; - for (int i = 0; i < size; ++i) { - memcpy(retLoc+i, valLoc+(size-i-1), 1); +class ObjectManagerError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, NO_MANAGER, MANAGER_MISMATCH, LOCK_OVERFLOW, BAD_THREAD + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; + +template +class ThreadsafeObjectLock; + +template +class ThreadsafeObject { + using Codes = ObjectManagerError::Codes; + + public: + ThreadsafeObject(T&& obj) + : _obj(std::make_shared(obj)) {} + + ThreadsafeObjectLock lock() { + return ThreadsafeObjectLock(this); } - return ret; -} */ + friend ThreadsafeObjectLock; -// using ByteVector = std::vector; + protected: + std::shared_ptr _obj; + mutable std::recursive_mutex _mutex; + +}; + +template +class ThreadsafeObjectLock { + public: + ThreadsafeObjectLock(const ThreadsafeObjectLock&) = delete; + ThreadsafeObjectLock operator=(const ThreadsafeObjectLock&) = delete; + ~ThreadsafeObjectLock() { + _manager->_mutex.unlock(); + } + + T* operator->() { + return _manager->_obj.get(); + } + + friend ThreadsafeObject; + + protected: + ThreadsafeObjectLock( + ThreadsafeObject* const manager_ + ) : _manager(manager_) { + if (!_manager) { + using Codes = ObjectManagerError::Codes; + THROW(ObjectManagerError(Codes::NO_MANAGER)); + } + _manager->_mutex.lock(); + } + ThreadsafeObject* const _manager; +}; } // namespace nb #endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index f2d0c8e..8af8796 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -33,8 +33,6 @@ static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); } - - static const bool LOGGER_RUNNING = RUN_LOGGER(logger); } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/src/Processes.cpp b/engine/NBCore/src/Processes.cpp index 744d96d..f0aec20 100644 --- a/engine/NBCore/src/Processes.cpp +++ b/engine/NBCore/src/Processes.cpp @@ -15,8 +15,15 @@ uint64_t GetPID() { return GetCurrentProcessId(); } #endif // _NB_TARGET_WINDOWS - #ifdef _NB_TARGET_LINUX #endif // _NB_TARGET_LINUX +#ifdef _NB_TARGET_WINDOWS +uint64_t GetTID() { + return GetCurrentThreadId(); +} +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX +#endif // _NB_TARGET_LINUX + } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index 8b13789..39fc680 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1 +1,27 @@ +#include "Utils.hpp" +namespace nb { + +using ObjectManagerCodes = ObjectManagerError::Codes; +const std::string ObjectManagerError::type = "nb::ObjectManagerError"; +const ErrorCodeMap ObjectManagerError::ErrorMessages({ + {ObjectManagerCodes::UNDEFINED, "Error"}, + { + ObjectManagerCodes::NO_MANAGER, + "Attempting to create object lock without lock manager" + }, + { + ObjectManagerCodes::MANAGER_MISMATCH, + "Attempting to delete object lock from mismatched lock manager" + }, + { + ObjectManagerCodes::LOCK_OVERFLOW, + "Too many object locks allocated" + }, + { + ObjectManagerCodes::BAD_THREAD, + "Attempting operation from a bad thread" + } +}); + +}; // namespace nb -- 2.43.0 From e4b164f29a78555506efaa299f633ac295c740c3 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 26 Jun 2026 02:43:16 -0500 Subject: [PATCH 11/18] Error system simplification --- engine/NBCore/CMakeLists.txt | 3 +- engine/NBCore/DataSink.hpp | 6 +- engine/NBCore/Errors.hpp | 275 +------------------------------ engine/NBCore/ErrorsImpl.hpp | 175 ++++++++++++++++++++ engine/NBCore/Logger.hpp | 83 +++++----- engine/NBCore/Utils.hpp | 38 +++++ engine/NBCore/src/Errors.cpp | 13 -- engine/NBCore/src/ErrorsImpl.cpp | 16 ++ engine/NBCore/src/Logger.cpp | 2 +- 9 files changed, 279 insertions(+), 332 deletions(-) create mode 100644 engine/NBCore/ErrorsImpl.hpp delete mode 100644 engine/NBCore/src/Errors.cpp create mode 100644 engine/NBCore/src/ErrorsImpl.cpp diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index ee3a13b..76e9249 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,5 +1,5 @@ toAbsolutePath(NB_CORE_SOURCE - ./src/Errors.cpp + ./src/ErrorsImpl.cpp ./src/Logger.cpp ./src/Processes.cpp ./src/StringUtils.cpp @@ -10,6 +10,7 @@ toAbsolutePath(NB_CORE_INCLUDE ./ANSITerm.hpp ./DataSink.hpp ./Errors.hpp + ./ErrorsImpl.hpp ./Logger.hpp ./Processes.hpp ./StringUtils.hpp diff --git a/engine/NBCore/DataSink.hpp b/engine/NBCore/DataSink.hpp index d3c5d25..155c48a 100644 --- a/engine/NBCore/DataSink.hpp +++ b/engine/NBCore/DataSink.hpp @@ -72,11 +72,11 @@ template class MultithreadedDataProcessor : public BufferedDataProcessor, ProcessorType> { using Base = BufferedDataProcessor, ProcessorType>; -public: + public: ~MultithreadedDataProcessor() { type_ptr->stop(); } bool isRunning() const noexcept override { - return this->_running && (_runningThread!=nullptr); + return this->_running; } bool run() override { if (!type_ptr->isRunning()) { @@ -98,7 +98,7 @@ public: return !type_ptr->isRunning(); } -protected: + protected: using Base::Base; unsigned int count() const { diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 89cc13b..8a6db60 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -2,281 +2,11 @@ #ifndef _NB_ERROR #define _NB_ERROR -#include -#include -#include -#include -#include - +#include "ErrorsImpl.hpp" #include "Logger.hpp" -#include "StringUtils.hpp" -#include "TypeTraits.hpp" namespace nb { -typedef std::unordered_map ErrorCodeMap; - -template -constexpr bool IsValidException_v = std::is_base_of_v; -template -using IsValidException = std::enable_if_t, bool>; - -template -class ErrorBase; - -template -class Error; - -template -constexpr bool IsValidNBError_v = std::is_base_of_v, T>; -template -using IsValidNBError = std::enable_if_t, bool>; - - -template<> -class ErrorBase { -public: - const unsigned int code; - const std::string msg; - const std::string type; - const std::shared_ptr trace; - const bool traceIsNBError; - - virtual std::string what() const noexcept = 0; - virtual std::shared_ptr make_shared() const noexcept = 0; - -protected: - template - ErrorBase(const ErrorBase& err) : ErrorBase(std::move(err)) {} - - template - ErrorBase(ErrorBase&& err) : ErrorBase( - err.code, - err.msg, - err.type, - (err.traceIsNBError) - ? static_cast(err.trace.get()) - : static_cast(err.trace.get()) - ) {} - - ErrorBase( - unsigned int code_, - std::string msg_, - std::string type_, - const std::exception* trace_ - ) noexcept : - code(code_), - msg(msg_), - type(type_), - trace{ trace_ ? - std::static_pointer_cast( - std::make_shared>(*trace_)) - : nullptr, - }, - traceIsNBError(false) - {} - - template, bool> = true> - ErrorBase( - unsigned int code_, - std::string msg_, - std::string type_, - const T* trace_ - ) noexcept : - code(code_), - msg(msg_), - type(type_), - trace{trace_ ? trace_->make_shared() : nullptr}, - traceIsNBError(true) - {} -}; - - -template -class ErrorBase : public ErrorBase { -private: - using Base = ErrorBase; - void inline check_asserts() { - static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, - "const std::unordered_map ErrorMessages must be " - "a class member." - ); - static_assert(std::is_enum_v, "enum Codes must be a class member."); - static_assert(std::is_same, unsigned int>::value, - "enum Codes must be of underlying type unsigned int." - ); - static_assert(std::is_same::value, - "const std::string type must be a class member." - ); - } - -public: - template - ErrorBase(const ErrorBase& cpy) : Base(cpy) { check_asserts(); } - - virtual std::shared_ptr make_shared() const noexcept override { - return std::static_pointer_cast( - std::make_shared(*this) - ); - } - - virtual std::string what() const noexcept override { - std::string ret = msg; - if (trace) { - std::string trace_msg; - if (traceIsNBError) { - trace_msg = std::static_pointer_cast(trace)->what(); - } else { - trace_msg = std::string(std::static_pointer_cast(trace)->what()); - } - ret += nb::NEWLINE + indent_strblock( - trace_msg, - nb::TABOVER, - nb::TABOVER+"Trace: " - ); - } - return ret; - } - - static const std::string type; - static const ErrorCodeMap ErrorMessages; - - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - - friend ErrorType; - friend Error; - -protected: - using Base::Base; - - template - ErrorBase( - unsigned int code_, - std::string msg_, - std::string type_, - const T* trace_ - ) : Base( - code_, - msg_, - type_, - trace_ - ) { check_asserts(); } -}; -template -const std::string ErrorBase::type = ErrorType::type; -template -const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; - - -template -class Error : public ErrorBase { - using Base = ErrorBase; -public: - template - Error( - unsigned int code_, - const T& trace_ - ) noexcept : Base( - code_, - ErrorType::ErrorMessages.at(code_), - ErrorType::type, - &trace_ - ) {} - - template - Error( - std::string msg_, - const ErrorBase& trace_ - ) noexcept : Base( - 0, - msg_, - ErrorType::type, - &trace_ - ) {} - - Error( - std::string msg_, - const std::exception& trace_ - ) noexcept : Base( - 0, - msg_, - ErrorType::type, - &trace_ - ) {} - - Error(unsigned int code_) noexcept : Base( - code_, - ErrorType::ErrorMessages.at(code_), - ErrorType::type, - NULLPTR - ) {} - - Error(std::string msg_) noexcept : Base( - 0, - msg_, - ErrorType::type, - NULLPTR - ) {} - - using Base::what; - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - using Base::type; - using Base::ErrorMessages; - -protected: - using Base::Base; - -}; - - -template<> -class Error : public ErrorBase> { - using Base = ErrorBase>; -public: - using Base::Base; - - Error(unsigned int code_=1) noexcept : Base( - code_, - ErrorMessages.at(code_), - type, - NULLPTR - ) {} - - Error(const std::exception& err) : Base( - Codes::STANDARD, - std::string(err.what()), - "std::exception", - nullptr - ) {} - - Error(std::string msg_) noexcept : Base( - Codes::UNDEFINED, - msg_, - type, - NULLPTR - ) {} - - enum Codes : unsigned int { - STANDARD, UNDEFINED - }; - - using Base::what; - - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - static const std::string type; - static const ErrorCodeMap ErrorMessages; -}; -} // namespace nb - #ifdef _NB_AUTOLOG #ifdef _NB_CODE_ERROR_LOCATIONS #ifndef LOG @@ -303,10 +33,11 @@ public: #ifndef THROW #ifdef _NB_AUTOLOG - #define THROW(args...) ERROR(args); throw args + #define THROW(args...) ERROR(args); nb::logger.stop(); throw args #else #define THROW(args...) throw args #endif // _NB_CODE_ERROR_LOCATIONS #endif // THROW +} // namespace nb #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/ErrorsImpl.hpp b/engine/NBCore/ErrorsImpl.hpp new file mode 100644 index 0000000..c5b8589 --- /dev/null +++ b/engine/NBCore/ErrorsImpl.hpp @@ -0,0 +1,175 @@ +#pragma once +#ifndef _NB_ERRORS_IMPL +#define _NB_ERRORS_IMPL + +#include +#include +#include +#include +#include + +#include "StringUtils.hpp" +#include "TypeTraits.hpp" + +namespace nb { + +typedef std::unordered_map ErrorCodeMap; + +template +class Error; + +class ErrorBase { + protected: + + public: + const unsigned int code; + const std::string msg; + const std::string type; + const std::shared_ptr trace; + + ErrorBase(const ErrorBase&) = default; + ErrorBase(const std::exception&) noexcept; + virtual std::string what() const noexcept { + std::string ret = msg; + if (trace) { + std::string trace_msg = msg; + ret += nb::NEWLINE + indent_strblock( + trace_msg, + nb::TABOVER, + nb::TABOVER+"Trace: " + ); + } + return ret; + } + + protected: + ErrorBase( + unsigned int code_, + std::string msg_, + std::string type_, + std::shared_ptr trace_ +) noexcept : + code(code_), + msg(msg_), + type(type_), + trace{trace_} +{} +}; + +template +class Error : public ErrorBase { + private: + void inline check_asserts() { + static_assert(std::is_same::value, + "const std::unordered_map ErrorMessages must be " + "a class member." + ); + static_assert(std::is_enum_v, "enum Codes must be a class member."); + static_assert(std::is_same, unsigned int>::value, + "enum Codes must be of underlying type unsigned int." + ); + static_assert(std::is_same::value, + "const std::string type must be a class member." + ); + } + + protected: + using ErrorBase::ErrorBase; + + public: + Error( + unsigned int code_, + const ErrorBase& trace_ + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + std::make_shared(trace_) + ) { check_asserts(); } + + Error( + std::string msg_, + const ErrorBase& trace_ + ) noexcept : ErrorBase( + 0, + msg_, + ErrorType::type, + std::make_shared(trace_) + ) { check_asserts(); } + + Error(unsigned int code_) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + nullptr + ) { check_asserts(); } + + Error(std::string msg_) noexcept : ErrorBase( + 0, + msg_, + ErrorType::type, + nullptr + ) { check_asserts(); } + + Error( + unsigned int code_, + const std::string& note_, + const ErrorBase& trace_ + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_) + " (" + note_ + ")", + ErrorType::type, + std::make_shared(trace_) + ) { check_asserts(); } + + Error(unsigned int code_, const std::string& note_) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_) + " (" + note_ + ")", + ErrorType::type, + nullptr + ) { check_asserts(); } + + using ErrorBase::what; + using ErrorBase::code; + using ErrorBase::msg; + using ErrorBase::trace; + using ErrorBase::type; +}; + + +template<> +class Error : public Error> { + using Base = Error>; + + public: + using Base::Base; + + Error(unsigned int code_=1) noexcept : Base(code_) {} + + Error(const std::exception& err) : Base( + Codes::STANDARD, + std::string(err.what()), + "std::exception", + nullptr + ) {} + + // fix + Error(std::string msg_) noexcept : Base( + Codes::UNDEFINED, + msg_ + ) {} + + enum Codes : unsigned int { + STANDARD, UNDEFINED + }; + + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; +} // namespace nb + +#endif // _NB_ERRORS_IMPL \ No newline at end of file diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index 2d64198..f4e79be 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -9,13 +9,13 @@ #include #include "DataSink.hpp" +#include "ErrorsImpl.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" namespace nb { -template class ErrorBase; typedef std::chrono::time_point< @@ -32,7 +32,8 @@ class LoggerBase using StreamType = ST; using LoggerType = Logger; using Base = MultithreadedDataProcessor; -public: + + public: bool run() override { if (!static_cast(this)->isRunning()) { this->_running = true; @@ -45,7 +46,9 @@ public: } return static_cast(this)->isRunning(); } -protected: + using Base::flush; + + protected: LoggerBase() = default; StreamType _ostream; @@ -73,7 +76,33 @@ public: ~DebugLogger() { static_cast(this)->stop(); } + template void log( + U val, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->write_message(val, 0x00, file, line); } + + template + void warn( + U val, + uint8_t lvl=0x01, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->write_message(val, lvl, file, line); } + + void error( + const ErrorBase& val, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->write_message(val, 0xFF, file, line); + static_cast(this)->flush(); + } + + protected: + std::vector _ostream; + void write_message( std::string msg, uint8_t lvl=0x00, std::string file="", @@ -91,56 +120,24 @@ public: } template - void log( + void write_message( char const(&msg) [N], uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { - static_cast(this)->log(std::string(msg), lvl, file, line); + static_cast(this)->write_message(std::string(msg), lvl, file, line); } - template - void log( - const ErrorBase& err, - uint8_t lvl=0xFF, + void write_message( + const ErrorBase& err, + uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { - static_cast(this)->log(err.what(), lvl, file, line); + static_cast(this)->write_message(err.what(), lvl, file, line); } - template - std::enable_if_t, void> log( - const T& err, - uint8_t lvl=0xFF, - std::string file="", - unsigned int line=0 - ) { - static_cast(this)->log(std::string(err.what()), lvl, file, line); - } - - template - void warn( - U val, - uint8_t lvl=0x01, - std::string file="", - unsigned int line=0 - ) { static_cast(this)->log(val, lvl, file, line); } - - template - void error( - U val, - std::string file="", - unsigned int line=0 - ) { - static_cast(this)->log(val, 0xFF, file, line); - static_cast(this)->flush(); - } - -protected: - std::vector _ostream; - }; class DefaultDebugLogger : public DebugLogger { @@ -150,7 +147,7 @@ class DefaultDebugLogger : public DebugLogger { template struct LogRow; -public: + public: using Base::Base; ~DefaultDebugLogger() { stop(); } @@ -166,6 +163,8 @@ protected: bool process(const LogEvent& msg); }; +extern const bool LOGGER_RUNNING; + #ifndef _NB_NO_LOGGER extern DefaultDebugLogger logger; #endif // _NB_NO_LOGGER diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index b7a477d..76ae1ed 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -9,6 +9,12 @@ namespace nb { +template +using SharedVector = std::vector>; + +template +using RValueVector = std::vector; + using ByteVector = std::vector; class ObjectManagerError : public Error { @@ -25,6 +31,38 @@ class ObjectManagerError : public Error { static const ErrorCodeMap ErrorMessages; }; +template +ByteVector vectorToBytes(const std::vector& vec) { + unsigned int num_bytes = vec.size() * sizeof(T); + ByteVector ret(num_bytes); + memcpy(ret.data(), vec.data(), num_bytes); + return ret; +} + +template +ByteVector concatVectorBytes(const std::vector& vec1, const std::vector& vec2) { + ByteVector vec1_raw = vectorToBytes(vec1); + ByteVector vec2_raw = vectorToBytes(vec2); + unsigned int vec1_raw_size = vec1_raw.size(); + unsigned int vec2_raw_size = vec2_raw.size(); + ByteVector ret(vec1_raw_size + vec2_raw_size); + memcpy(ret.data(), vec1_raw.data(), vec1_raw_size); + memcpy(ret.data() + vec1_raw_size, vec2_raw.data(), vec2_raw_size); + return ret; +} + +template +std::vector bytesToVector(const ByteVector& vec) { + if (vec.size() % sizeof(T) != 0) { + THROW(std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">.")); + } + unsigned int num_elmts = vec.size() / sizeof(T); + std::vector ret(num_elmts); + memcpy(ret.data(), vec.data(), vec.size()); + + return ret; +} + template class ThreadsafeObjectLock; diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp deleted file mode 100644 index e5b22fa..0000000 --- a/engine/NBCore/src/Errors.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "Errors.hpp" -#include "TypeTraits.hpp" - -namespace nb { - -const std::string Error<>::type = "nb::Error"; - -const ErrorCodeMap Error::ErrorMessages = { - {Error::Codes::STANDARD, "std::exception"}, - {Error::Codes::UNDEFINED, "Error"} -}; - -} diff --git a/engine/NBCore/src/ErrorsImpl.cpp b/engine/NBCore/src/ErrorsImpl.cpp new file mode 100644 index 0000000..a36b110 --- /dev/null +++ b/engine/NBCore/src/ErrorsImpl.cpp @@ -0,0 +1,16 @@ +#include "ErrorsImpl.hpp" + +namespace nb { + +const std::string Error<>::type = "nb::Error"; +const ErrorCodeMap Error<>::ErrorMessages = { + {Error::Codes::STANDARD, "std::exception"}, + {Error::Codes::UNDEFINED, "Error"} +}; + +//ErrorBase:: + +ErrorBase::ErrorBase(const std::exception& exception_) noexcept +: ErrorBase(Error(exception_)) {} + +} diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 8af8796..70c8ff8 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -33,6 +33,6 @@ static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); } -static const bool LOGGER_RUNNING = RUN_LOGGER(logger); +const bool LOGGER_RUNNING = RUN_LOGGER(logger); } // namespace nb \ No newline at end of file -- 2.43.0 From 81bffb7511f0c08d878e159b28cb47b4a2c5d2f3 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Mon, 8 Jun 2026 03:20:51 -0500 Subject: [PATCH 12/18] Large OpenGL Object handling overhaul --- engine/NBGraphics/Buffers.hpp | 463 ++++++++++--------------- engine/NBGraphics/CMakeLists.txt | 20 +- engine/NBGraphics/Camera.hpp | 5 +- engine/NBGraphics/GLLoad.hpp | 1 - engine/NBGraphics/OGLObjects.hpp | 45 +++ engine/NBGraphics/Textures.hpp | 61 ++++ engine/NBGraphics/VAOManager.hpp | 75 ---- engine/NBGraphics/VertexArray.hpp | 176 ++++++++++ engine/NBGraphics/Window.hpp | 3 +- engine/NBGraphics/src/Buffers.cpp | 16 + engine/NBGraphics/src/Camera.cpp | 5 +- engine/NBGraphics/src/OGLObjects.cpp | 11 + engine/NBGraphics/src/Textures.cpp | 10 + engine/NBGraphics/src/VAOManager.cpp | 225 ------------ engine/NBGraphics/src/VertexArray.cpp | 222 ++++++++++++ engine/NBGraphics/tests/CMakeLists.txt | 16 + engine/NBGraphics/tests/TestWindow.cpp | 6 + 17 files changed, 772 insertions(+), 588 deletions(-) create mode 100644 engine/NBGraphics/OGLObjects.hpp create mode 100644 engine/NBGraphics/Textures.hpp delete mode 100644 engine/NBGraphics/VAOManager.hpp create mode 100644 engine/NBGraphics/VertexArray.hpp create mode 100644 engine/NBGraphics/src/OGLObjects.cpp create mode 100644 engine/NBGraphics/src/Textures.cpp delete mode 100644 engine/NBGraphics/src/VAOManager.cpp create mode 100644 engine/NBGraphics/src/VertexArray.cpp create mode 100644 engine/NBGraphics/tests/CMakeLists.txt create mode 100644 engine/NBGraphics/tests/TestWindow.cpp diff --git a/engine/NBGraphics/Buffers.hpp b/engine/NBGraphics/Buffers.hpp index 58e8c42..4df38f3 100644 --- a/engine/NBGraphics/Buffers.hpp +++ b/engine/NBGraphics/Buffers.hpp @@ -4,15 +4,17 @@ #include "GLLoad.hpp" +#include #include #include #include -#include +#include +#include + +#include "OGLObjects.hpp" namespace nb { - -typedef std::vector RawVec; static uint8_t GLSLTypeSize(GLenum type) { switch(type) { @@ -35,51 +37,30 @@ static uint8_t GLSLTypeSize(GLenum type) { } } -struct VertexAttributePointer { - GLuint buffer = 0; - int32_t offset = 0; - GLsizei stride = -1; - GLuint divisor = 0; -}; - -struct VertexAttribute { - GLint GLSLSize; - GLenum GLSLType; - GLboolean GLSLNormalization; - VertexAttributePointer ptr; -}; - -static bool isIndexInVertexAttribute(int i, const VertexAttribute& va) { - if ((i -= va.ptr.offset) < 0) { return false; } - return (i%va.ptr.stride) < GLSLTypeSize(va.GLSLType) * va.GLSLSize; -} - -typedef std::vector VertexAttributeList; - template -RawVec vectorToRaw(const std::vector& vec) { +ByteVector vectorToRaw(const std::vector& vec) { unsigned int num_bytes = vec.size() * sizeof(T); - RawVec ret(num_bytes); + ByteVector ret(num_bytes); memcpy(ret.data(), vec.data(), num_bytes); return ret; } template -RawVec concatVectorsToRaw(const std::vector& vec1, const std::vector& vec2) { - RawVec vec1_raw = vectorToRaw(vec1); - RawVec vec2_raw = vectorToRaw(vec2); +ByteVector concatVectorsToRaw(const std::vector& vec1, const std::vector& vec2) { + ByteVector vec1_raw = vectorToRaw(vec1); + ByteVector vec2_raw = vectorToRaw(vec2); unsigned int vec1_raw_size = vec1_raw.size(); unsigned int vec2_raw_size = vec2_raw.size(); - RawVec ret(vec1_raw_size + vec2_raw_size); + ByteVector ret(vec1_raw_size + vec2_raw_size); memcpy(ret.data(), vec1_raw.data(), vec1_raw_size); memcpy(ret.data() + vec1_raw_size, vec2_raw.data(), vec2_raw_size); return ret; } template -std::vector rawToVector(const RawVec& vec) { +std::vector rawToVector(const ByteVector& vec) { if (vec.size() % sizeof(T) != 0) { - throw std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">."); + THROW(std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">.")); } unsigned int num_elmts = vec.size() / sizeof(T); std::vector ret(num_elmts); @@ -88,278 +69,206 @@ std::vector rawToVector(const RawVec& vec) { return ret; } -class BufferError : public std::runtime_error { -public: - const bool error; - BufferError(const std::string& msg, const std::string& file="", int line=-1) - : std::runtime_error(NB::formatDebugString(msg, file, line)), error(true) {} - BufferError(bool isError=true) : std::runtime_error(""), error(isError) {} -}; - - -template -class OpenGLObject { -public: - OpenGLObject(OpenGLObject&&) = default; - OpenGLObject& operator=(OpenGLObject&&) = default; - ~OpenGLObject() { remove(); } +class BufferError : public Error { + using Base = Error; - virtual void bind() const = 0; - virtual void unbind() const = 0; - virtual bool isInitialized() const = 0; - GLuint id() const { return _id; } - -protected: - OpenGLObject() = default; - OpenGLObject(const OpenGLObject&) = delete; - OpenGLObject& operator=(const OpenGLObject&) = delete; - - virtual void remove() const = 0; - - GLuint _id; -}; - -class VAO : public virtual OpenGLObject { -public: - using Base = OpenGLObject; + public: using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, DATA_OVERFLOW, INVALID_BUFFER, HANDLE_OVERWRITE + }; - VAO() { glGenVertexArrays(1, &_id); } - - void bind() const { glBindVertexArray(_id); } - void unbind() const { glBindVertexArray(0); } - - -protected: - using Base::_id; - const - - void remove() { glDeleteVertexArrays(1, &_id); } - + static const std::string type; + static const ErrorCodeMap ErrorMessages; }; template -class Buffer : public virtual OpenGLObject> { -public: - using Base = OpenGLObject; - using Base::Base; +class Buffer : public OpenGLObject { + using Codes = BufferError::Codes; - Buffer(GLenum usage_ = GL_STATIC_DRAW) : usage(usage_) { glGenBuffers(1, &_id); } + public: + using OpenGLObject::OpenGLObject; + + Buffer() = default; + Buffer(Buffer&& other) { + *this = std::move(other); + } + Buffer& operator=(Buffer&& rhs) { + if (_id) { THROW(BufferError(Codes::HANDLE_OVERWRITE)); } + _id = rhs._id; + _usage = rhs._usage; + _size = rhs._size; - void bind() const { glBindBuffer(GLTarget, _id); } - void unbind() const { glBindBuffer(GLTarget, 0); } - void data(void* data_, size_t size) const { glBufferData(GLTarget, size, data_, usage); } - void data(nb::ByteVector& data_) const { glBufferData(GLTarget, data_.size(), data_.data(), usage); } - void invalidate() const { glInvalidateBufferData(_id); } + rhs._id = 0; + rhs._usage = GL_STATIC_DRAW; + rhs._size = 0; + return *this; + } + virtual void bind() const override { + if (_id) { + glBindBuffer(Target, _id); + } + THROW(BufferError(Codes::INVALID_BUFFER)); + } + virtual void unbind() const override { glBindBuffer(Target, 0); } + virtual GLenum usage() const { return _usage; } + virtual GLenum usage(GLenum usage_) { + _usage = usage_; + data(data(), _usage); + return _usage; + } + virtual size_t size() const { return _size; } + virtual ByteVector data() const { + bind(); + ByteVector ret(_size); + glGetBufferSubData(Target, 0, _size, ret.data()); + return ret; + } + virtual void data( + const void* data_, + GLsizei size_, + GLenum usage_=GL_STATIC_DRAW + ) { + declare(); + bind(); + glBufferData(Target, size_, data_, usage_); + _size = size_; + _usage = usage_; + } + virtual void data(const ByteVector& data_, GLenum usage_=GL_STATIC_DRAW) { + data(Target, data_.size(), data_.data(), usage_); - const GLenum GLTarget = BufferType::GLTarget; - GLenum usage; + } + virtual void subdata(void* data_, GLsizeiptr size_, GLintptr offset_=0) { + bind(); + if (offset_+size_ <= _size) { + THROW(BufferError(BufferError::Codes::DATA_OVERFLOW)); + } + glBufferSubData(Target, offset_, size_, data_); + } + virtual void subdata(ByteVector& data_, GLintptr offset_=0) { + bind(); + size_t size_ = data_.size(); + if (offset_+size_ <= _size) { + THROW(BufferError(BufferError::Codes::DATA_OVERFLOW)); + } + glBufferSubData(Target, offset_, data_.size(), data_.data()); + } + // virtual void clear() const { glClearBufferData(Target, ) } + static const GLenum Target; + + protected: + using OpenGLObject::_id; + GLenum _usage = GL_STATIC_DRAW; + size_t _size; + virtual GLuint declare() override { + if (!_id) { + glGenBuffers(1, &_id); + } + return _id; + } + virtual void remove() override { + if (_id) { + glDeleteBuffers(1, &_id); + _id = 0; + } + } + +}; + +template +const GLenum Buffer::Target = BufferType::Target; + +template +class ImmutableBuffer : public virtual Buffer { + public: + using Base = Buffer; + using Base::Target; + using Base::bind; + + ImmutableBuffer() = default; + ImmutableBuffer(size_t size_, GLenum usage_ = GL_STATIC_DRAW, GLbitfield flags_=0x0) : size(size_), Base::usage(usage_) { + glBufferStorage(Target, size, nullptr, flags_); + } + + std::weak_ptr map(GLbitfield access_) { + if (_map && _mapAccess != access_) { unmap(); } + _mapAccess = access_; + if (!_map) { + bind(); + glMapBuffer(Target, _mapAccess); + } + return _map; + } + void unmap() { + bind(); + glUnmapBuffer(Target); + _map.reset(); + } + + const size_t size; protected: using Base::_id; - void remove() { glDeleteBuffers(1, &_id); } + std::shared_ptr _map = nullptr; + GLbitfield _mapAccess = 0; }; -class VertexBuffer : public virtual Buffer { -public: +template +class ArrayBuffer : public Buffer> { + using Base = Buffer>; + using BufferType = Base; - static const GLenum GLTarget = GL_ARRAY_BUFFER; -protected: + public: + using Base::Base; + using Base::data; + ArrayBuffer(const ByteVector&, GLenum usage_=GL_STATIC_DRAW); + + static const GLenum Target = GL_ARRAY_BUFFER; + + protected: + using Base::_usage; +}; + +template <> +class ArrayBuffer +: public virtual ArrayBuffer, public virtual ImmutableBuffer> { + using Base = ArrayBuffer; + using BufferType = ImmutableBuffer>; + using BufferType::BufferType; + + public: + using Base::Target; }; -class ElementBuffer : public virtual Buffer { -public: +template +class ElementBuffer : public virtual Buffer> { + using Base = Buffer>; + using BufferType = Base; + + public: + using Base::Base; + static const GLenum Target = GL_ELEMENT_ARRAY_BUFFER; - static const GLenum GLTarget = GL_ELEMENT_ARRAY_BUFFER; - -protected: + protected: }; -/* -class Buffer : public OpenGLObject { -public: - Buffer( - GLenum buffer_type, - GLenum usage=GL_STATIC_DRAW - ) : _type(buffer_type), _usage(usage) { - glGenBuffers(1, &_id); - } - Buffer( - const RawVec& init_data, - GLenum buffer_type, - GLenum usage=GL_STATIC_DRAW - ) : _type{buffer_type}, _usage{usage} { data(init_data); } - Buffer( - unsigned int size, - GLenum buffer_type, - GLenum usage=GL_STATIC_DRAW - ) : Buffer(RawVec(size), buffer_type, usage) {} +template <> +class ElementBuffer +: public virtual ElementBuffer, public virtual ImmutableBuffer> { + using Base = ElementBuffer; + using BufferType = ImmutableBuffer>; - Buffer(Buffer&& rhs) { *this = std::move(rhs); } - Buffer& operator=(Buffer&& rhs) { - remove(); - _usage = rhs._usage; - _id = rhs._id; - rhs._id = 0; - return *this; - } - - GLenum usage() const { return _usage; } - unsigned int id() const { return _id; } - GLuint size() const { return _size; } - bool isInitialized() const override { return _id && glIsBuffer(_id) && bool(_size); } - RawVec data() const { - RawVec ret(_size); - bind(); - glGetBufferSubData(_type, 0, _size, ret.data()); - return ret; - } - void bind() const override { glBindBuffer(_type, _id); } - void unbind() const override { glBindBuffer(_type, 0); } - - GLenum usage(GLenum usage) { - _usage=usage; - data(data()); - return _usage; - } - void data(const RawVec& set_data) { - if (!glfwGetCurrentContext()) { - THROW_BUFFER_ERROR("No OpenGL context."); - } - bind(); - glBufferData(_type, set_data.size(), set_data.data(), _usage); - _size = set_data.size(); - } - void data(const RawVec& newData, unsigned int offset) { - if (newData.size()+offset > _size) { - THROW_BUFFER_ERROR("Attempting to overflow buffer of capacity " + std::to_string(_size) + "."); - } - bind(); - glBufferSubData(_type, offset, newData.size(), newData.data()); - } - void data(void* src, unsigned int offset, unsigned int size) { - if (size+offset > _size) { - THROW_BUFFER_ERROR("Attempting to overflow buffer of capacity " + std::to_string(_size) + "."); - } - bind(); - glBufferSubData(_type, offset, size, src); - } - -protected: - virtual void remove() const override { - unbind(); - if (_id) { glDeleteBuffers(1, &_id); } - } - - using OpenGLObject::_id; - GLenum _type; - GLenum _usage; - unsigned int _size = 0; -}; - - -class Texture : public OpenGLObject { -public: - Texture(GLenum tar=GL_TEXTURE_2D) : _target(tar) { glGenTextures(1, &_id); } - - Texture(Texture&& rhs) { *this=std::move(rhs); } - Texture& operator=(Texture&& rhs) { - _target = rhs._target; - _id = rhs._id; - rhs._id = 0; - return *this; - } - - void bind() const override { glBindTexture(_target, _id); } - void unbind() const override { glBindTexture(_target, 0); } - bool isInitialized() const override { return _id && glIsTexture(_id); } - -protected: - using OpenGLObject::_id; - GLenum _target; -}; - -class Framebuffer : public OpenGLObject { -public: - - Framebuffer(GLenum tar=GL_FRAMEBUFFER) : _target(tar) { glGenFramebuffers(1, &_id); } - - Framebuffer(Framebuffer&& rhs) { *this=std::move(rhs); } - Framebuffer& operator=(Framebuffer&& rhs) { - remove(); - _target = rhs._target; - _id = rhs._id; - rhs._id = 0; - return *this; - } - - void bind() const override { glBindFramebuffer(_target, _id); } - void unbind() const override { glBindFramebuffer(_target, 0); } - bool isInitialized() const override { return _id && glIsFramebuffer(_id); } - GLenum status() const { - bind(); - return glCheckFramebufferStatus(_target); - } - - -protected: - virtual void remove() const override { - unbind(); - if (_id) { glDeleteFramebuffers(1, &_id); } - } - using OpenGLObject::_id; - GLenum _target; -}; - -class Renderbuffer : public OpenGLObject { -public: - Renderbuffer(unsigned int x, unsigned int y, GLenum format=GL_RGBA32F, unsigned int multi=0) : Renderbuffer() { - storage(x, y, format, multi); - } - Renderbuffer() { glGenRenderbuffers(1, &_id); } - - - Renderbuffer(Renderbuffer&& rhs) { *this = std::move(rhs); } - Renderbuffer& operator=(Renderbuffer&& rhs) { - _format = rhs._format; - _id = rhs._id; - rhs._id = 0; - return *this; - } - - virtual void bind() const override { glBindRenderbuffer(GL_RENDERBUFFER, _id); } - virtual void unbind() const override { glBindRenderbuffer(GL_RENDERBUFFER, _id); } - virtual bool isInitialized() const override { return _id && glIsRenderbuffer(_id); } - - void storage(unsigned int x, unsigned int y, GLenum format=GL_RGBA32F, unsigned int multi=0) { - _sizex = x; - _sizey = y; - _format = format; - _multisample = multi; - bind(); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, _multisample, _format, _sizex, _sizey); - } - - -protected: - virtual void remove() const override { - unbind(); - if (_id) { glDeleteRenderbuffers(1, &_id); } - } - - using OpenGLObject::_id; - GLenum _format; - unsigned int _sizex{0}; - unsigned int _sizey{0}; - unsigned int _multisample{0}; + public: + using BufferType::BufferType; + using Base::Target; }; -*/ - } // namespace NB #endif // _NB_BUFFER diff --git a/engine/NBGraphics/CMakeLists.txt b/engine/NBGraphics/CMakeLists.txt index 6a22f25..f799880 100644 --- a/engine/NBGraphics/CMakeLists.txt +++ b/engine/NBGraphics/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(./.) - find_package(OpenGL) add_subdirectory(${GLFW_PATH} ${GLFW_PATH}/build) @@ -10,8 +8,11 @@ set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) toAbsolutePath(NB_GRAPHICS_SOURCE - ./src/Window.cpp ./src/Buffers.cpp + ./src/OGLObjects.cpp + ./src/Textures.cpp + ./src/VertexArray.cpp + ./src/Window.cpp ) toAbsolutePath(NB_GRAPHICS_INCLUDE @@ -19,8 +20,10 @@ toAbsolutePath(NB_GRAPHICS_INCLUDE ./Camera.hpp ./Draw.hpp ./GLLoad.hpp + ./OGLObjects.hpp ./shader.hpp - ./VAOManager.hpp + ./Textures.hpp + ./VertexArray.hpp ./Window.hpp ) @@ -31,4 +34,11 @@ add_library(NBGraphics ${NB_GRAPHICS_SOURCE} ${GLAD_PATH}/src/glad.c ) -target_link_libraries(NBGraphics glfw3) +target_link_libraries(NBGraphics glfw) + +target_include_directories(NBGraphics PUBLIC ./.) + +if (NB_BUILD_TESTS) + add_subdirectory(./tests) +endif() + diff --git a/engine/NBGraphics/Camera.hpp b/engine/NBGraphics/Camera.hpp index 35e109d..8e31c8c 100644 --- a/engine/NBGraphics/Camera.hpp +++ b/engine/NBGraphics/Camera.hpp @@ -2,13 +2,14 @@ #ifndef _NB_CAMERA #define _NB_CAMERA -#include +#include "GLLoad.hpp" + #include #include #include #include -namespace NB { +namespace nb { class Camera { public: diff --git a/engine/NBGraphics/GLLoad.hpp b/engine/NBGraphics/GLLoad.hpp index 5936ed9..7989fb3 100644 --- a/engine/NBGraphics/GLLoad.hpp +++ b/engine/NBGraphics/GLLoad.hpp @@ -5,7 +5,6 @@ #include #include -#include #include namespace NB { diff --git a/engine/NBGraphics/OGLObjects.hpp b/engine/NBGraphics/OGLObjects.hpp new file mode 100644 index 0000000..64cd302 --- /dev/null +++ b/engine/NBGraphics/OGLObjects.hpp @@ -0,0 +1,45 @@ +#pragma once +#ifndef _NB_OGL_OBJECTS +#define _NB_OGL_OBJECTS + +#include "GLLoad.hpp" + +#include + +namespace nb { + +class OGLError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, HANGING_OBJECT + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; + +class OpenGLObject { + public: + OpenGLObject(const OpenGLObject&) = delete; + OpenGLObject& operator=(const OpenGLObject&) = delete; + ~OpenGLObject() { remove(); } + + virtual void bind() const = 0; + virtual void unbind() const = 0; + GLuint id() const { return _id; } + + protected: + OpenGLObject() = default; + + virtual GLuint declare() = 0; + virtual void remove() { this->remove(); }; + + GLuint _id; +}; + +} // namespace nb +#endif // _NB_OGL_OBJECTS \ No newline at end of file diff --git a/engine/NBGraphics/Textures.hpp b/engine/NBGraphics/Textures.hpp new file mode 100644 index 0000000..8984e72 --- /dev/null +++ b/engine/NBGraphics/Textures.hpp @@ -0,0 +1,61 @@ +#pragma once +#ifndef _NB_TEXTURES +#define _NB_TEXTURES + +#include "Buffers.hpp" +#include "OGLObjects.hpp" + +namespace nb { + +template +class TextureBuffer : public virtual Buffer> { + using Base = Buffer>; + using BufferType = Base; + + public: + using Base::Base; + static const GLenum Target = GL_TEXTURE_BUFFER; + + protected: + +}; + +template <> +class TextureBuffer +: public virtual TextureBuffer, public virtual ImmutableBuffer> { + using Base = TextureBuffer; + using BufferType = ImmutableBuffer>; + + public: + using BufferType::BufferType; + using Base::Target; +}; + +class Texture : public OpenGLObject { + using Base = OpenGLObject; +public: + using Base::Base; + using Base::id; + + Texture(GLenum); + + virtual void bind() const override { glBindTexture(target, _id); } + virtual void unbind() const override { glBindTexture(target, 0); } + + const GLenum target; + + friend Base; + + protected: + using Base::_id; + + virtual void remove() override { + if (_id) { + glDeleteTextures(0, &_id); + } + } + +}; + +} // namespace nb +#endif // _NB_TEXTURES \ No newline at end of file diff --git a/engine/NBGraphics/VAOManager.hpp b/engine/NBGraphics/VAOManager.hpp deleted file mode 100644 index 142882c..0000000 --- a/engine/NBGraphics/VAOManager.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#ifndef _NB_VAO_MANAGER -#define _NB_VAO_MANAGER - -#include - -#include -#include -#include - -#include "Buffers.h" - -#define THROW_VAO_ERROR(msg) throw VAOError(msg, __FILE__, __LINE__); - -namespace NB { - -class VAOError : public std::runtime_error { -public: - const bool error; - VAOError(const std::string& msg, const std::string& file="", int line=-1) - : std::runtime_error(NB::formatDebugString(msg, file, line)), error(true) {} - VAOError(bool isError=true) : std::runtime_error(""), error(isError) {} -}; - -class VAOManager : public OpenGLObject { -public: - typedef std::shared_ptr BufferManagerPointer; - //typedef BufferManager BufferManagerPointer; - - VAOManager(); - VAOManager( - std::vector, - BufferManagerPointer elmt_buf = nullptr, - const VertexAttributeList& vert_attrs = {} - ); - VAOManager( - BufferManagerPointer vert_bufs, - BufferManagerPointer elmt_buf = nullptr, - const VertexAttributeList& vert_attrs = {} - ) : VAOManager(std::vector(1, vert_bufs), elmt_buf, vert_attrs) {} - - VAOManager(VAOManager&& rhs); - VAOManager& operator=(VAOManager&& rhs); - - VertexAttributeList getLayout() const; - GLuint id() const; - unsigned int vertSize(GLuint) const; - std::vector getVertexBuffers() const; - bool isInitialized() const override; - RawVec attributeData(unsigned int); - - RawVec attributeData(unsigned int, const RawVec&); - void bind() const; - void unbind() const; - void addVBO(BufferManagerPointer); - void changeEBO(BufferManagerPointer); - VertexAttributeList addVertexAttributes(const VertexAttributeList&); - VertexAttributeList addVertexAttributes(VertexAttribute); - VertexAttributeList generate(); - VertexAttributeList generate(VertexAttributeList); - VertexAttributeList changeLayout(unsigned int, VertexAttributePointer); - - VAOError checkValid(const VertexAttributeList&); - -private: - void remove() const override; - - using OpenGLObject::_id; - std::map _vert_buffers; - BufferManagerPointer _elmt_buffer = nullptr; - VertexAttributeList _vert_attrs; -}; - -} // namespace NB -#endif // _NB_VAO_MANAGER \ No newline at end of file diff --git a/engine/NBGraphics/VertexArray.hpp b/engine/NBGraphics/VertexArray.hpp new file mode 100644 index 0000000..30afe3a --- /dev/null +++ b/engine/NBGraphics/VertexArray.hpp @@ -0,0 +1,176 @@ +#pragma once +#ifndef _NB_VERTEX_ARRAY +#define _NB_VERTEX_ARRAY + +#include "GLLoad.hpp" + +#include + +#include "Buffers.hpp" +#include "OGLObjects.hpp" + + +namespace nb { + +struct VertexAttributeLayout { + int32_t offset = 0; + GLsizei stride = 0; + GLuint divisor = 0; +}; + +struct VertexAttribute { + GLint GLSLSize; + GLenum GLSLType; + GLboolean GLSLNormalization; + VertexAttributeLayout layout; +}; + +struct VertexAttributePointer; + +static bool isIndexInVertexAttribute(int i, const VertexAttribute& va) { + if ((i -= va.layout.offset) < 0) { return false; } + return (i%va.layout.stride) < GLSLTypeSize(va.GLSLType) * va.GLSLSize; +} + +typedef std::vector VertexAttributeList; +typedef std::vector VertexAttributePointerList; + +class VAOError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, INVALID_ATTRIBUTE, INVALID_VAO + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; + +template +class VertexBuffer : public ArrayBuffer{ + using Base = ArrayBuffer; + + public: + template + VertexBuffer(const VertexAttributeList& vas, Args... args) + : attributes(vas) { + if (sizeof...(Args)) { + data(args...); + } + } + + using Base::Target; + const VertexAttributeList attributes; + + protected: + using Base::_usage; + +}; + +template <> +class VertexBuffer +: public virtual VertexBuffer, public virtual ImmutableBuffer> { + using Base = ArrayBuffer; + using BufferType = ImmutableBuffer>; + using BufferType::BufferType; + + public: + using Base::Target; + +}; + +struct VertexAttributePointer { + VertexAttribute attribute; + VertexBuffer* buffer; + GLuint index; +}; + +class VAO : public OpenGLObject { + using Base = OpenGLObject; + using Codes = VAOError::Codes; + + public: + using Base::Base; + VAO() = default; + VAO(const VertexAttributePointerList&); + VAO(VAO&&); + + VAO& operator=(VAO&&); + + virtual void bind() const override { + if(_id) { + glBindVertexArray(_id); + } else { + THROW(Codes::INVALID_VAO); + } + } + virtual void unbind() const override { glBindVertexArray(0); } + + VertexAttributePointerList attributes() const; + VertexAttributePointerList attributes(const VertexAttributePointerList&); + VertexAttributePointer attr(GLuint) const; + void enable() const; + void enable(GLuint) const; + void disable() const; + void disable(GLuint) const; + + protected: + using Base::_id; + VertexAttributePointerList _attrs; + + virtual void remove() override { + if(_id) { + disable(); + bind(); + glDeleteVertexArrays(1, &_id); + _id = 0; + } + } + virtual GLuint declare() override { + if (!_id) { + glGenVertexArrays(1, &_id); + } + return _id; + } + +}; + +class VertexGroup { + public: + VertexGroup(VertexGroup&&); + VertexGroup& operator=(VertexGroup&&); + + void bind() const { + _elmt_buf.bind(); + _vao.bind(); + } + void unbind() const { + _vao.bind(); + _elmt_buf.unbind(); + } + + VertexBuffer& buffer(size_t); + size_t buffer(VertexBuffer&&); + std::vector>> buffers(); + size_t buffers(std::vector>&&); + VertexBuffer&& dropBuffer(size_t); + + VertexAttributePointer attribute(size_t) const; + void enableAttr(GLuint); + void disableAttr(GLuint); + void enableBuffer(size_t); + void disableBuffer(size_t); + void enable(); + void disable(); + + protected: + std::vector>> _vertex_data; + ElementBuffer _elmt_buf; + VAO _vao; +}; + +} // namespace nb +#endif // _NB_VERTEX_ARRAY \ No newline at end of file diff --git a/engine/NBGraphics/Window.hpp b/engine/NBGraphics/Window.hpp index 22a82f8..88e84df 100644 --- a/engine/NBGraphics/Window.hpp +++ b/engine/NBGraphics/Window.hpp @@ -4,12 +4,13 @@ #include "GLLoad.hpp" -#include #include #include #include #include +#include + namespace nb { class GLError : public std::runtime_error { diff --git a/engine/NBGraphics/src/Buffers.cpp b/engine/NBGraphics/src/Buffers.cpp index 24f9115..3f80a45 100644 --- a/engine/NBGraphics/src/Buffers.cpp +++ b/engine/NBGraphics/src/Buffers.cpp @@ -2,4 +2,20 @@ namespace nb { +using BufferErrorCodes = BufferError::Codes; +const std::string BufferError::type = "nb::BufferError"; +const ErrorCodeMap BufferError::ErrorMessages = { + { BufferErrorCodes::UNDEFINED, "Error" }, + { BufferErrorCodes::DATA_OVERFLOW, "Attempting buffer overflow" }, + { BufferErrorCodes::INVALID_BUFFER, "Attempting operation on invalid buffer" }, + {BufferErrorCodes::HANDLE_OVERWRITE, "Attempting to overwrite active buffer"} + +}; + +template<> +ArrayBuffer::ArrayBuffer(const ByteVector& data_, GLenum usage_) +: BufferType() { + data(data_, usage_); +} + } \ No newline at end of file diff --git a/engine/NBGraphics/src/Camera.cpp b/engine/NBGraphics/src/Camera.cpp index 8431597..e7aa711 100644 --- a/engine/NBGraphics/src/Camera.cpp +++ b/engine/NBGraphics/src/Camera.cpp @@ -1,5 +1,6 @@ -#include "Camera.h" -namespace NB { +#include "Camera.hpp" + +namespace nb { // Camera class Camera::Camera(const Vec3& pos, const Vec3& tar, const Vec3& up) { diff --git a/engine/NBGraphics/src/OGLObjects.cpp b/engine/NBGraphics/src/OGLObjects.cpp new file mode 100644 index 0000000..d66a2dc --- /dev/null +++ b/engine/NBGraphics/src/OGLObjects.cpp @@ -0,0 +1,11 @@ +#include "OGLObjects.hpp" + +namespace nb { + +const std::string OGLError::type = "nb::OGLError"; +const ErrorCodeMap OGLError::ErrorMessages = { + { OGLError::Codes::UNDEFINED, "Error" }, + {OGLError::Codes::HANGING_OBJECT, "Attempting to leave a hanging OpenGL object"} +}; + +} // namespace nb \ No newline at end of file diff --git a/engine/NBGraphics/src/Textures.cpp b/engine/NBGraphics/src/Textures.cpp new file mode 100644 index 0000000..9b448c7 --- /dev/null +++ b/engine/NBGraphics/src/Textures.cpp @@ -0,0 +1,10 @@ +#include "Textures.hpp" + +namespace nb{ + +Texture::Texture(GLenum target_) : target(target_) { + glGenTextures(1, &_id); +} + + +} // namespace nb \ No newline at end of file diff --git a/engine/NBGraphics/src/VAOManager.cpp b/engine/NBGraphics/src/VAOManager.cpp deleted file mode 100644 index c9ea7d5..0000000 --- a/engine/NBGraphics/src/VAOManager.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "VAOManager.hpp" - -namespace NB { - -using BufferManagerPointer = std::shared_ptr; - -VAOManager::VAOManager() { glGenVertexArrays(1, &_id); } - -VAOManager::VAOManager( - std::vector vert_bufs, - BufferManagerPointer elmt_buf, - const VertexAttributeList& vert_attrs -) : VAOManager() { - _elmt_buffer = elmt_buf; - for (BufferManagerPointer vb : vert_bufs) { - _vert_buffers[vb->id()] = vb; - } - if (vert_attrs.size()!=0) { - generate(vert_attrs); - } -} - -VAOManager::VAOManager(VAOManager&& rhs) { *this = std::move(rhs); } - -VAOManager& VAOManager::operator=(VAOManager&& rhs) { - remove(); - _vert_buffers = rhs._vert_buffers; - _elmt_buffer = rhs._elmt_buffer; - _vert_attrs = rhs._vert_attrs; - return *this; -} - -VertexAttributeList VAOManager::getLayout() const { return _vert_attrs; } - -GLuint VAOManager::id() const { return _id; } - -bool VAOManager::isInitialized() const { - return _id && glIsVertexArray(_id); -} - -void VAOManager::remove() const { - bind(); - for (int i{0}; i < _vert_attrs.size(); ++i) { - glDisableVertexAttribArray(i); - } - unbind(); - glDisableVertexAttribArray(_id); -} - -unsigned int VAOManager::vertSize(GLuint id) const { - unsigned int size = 0; - for (const VertexAttribute& va : _vert_attrs) { - if (va.ptr.buffer == id) { - size += va.GLSLSize * GLSLTypeSize(va.GLSLType); - } - } - return size; -} - -std::vector VAOManager::getVertexBuffers() const { - std::vector ret; - for (const auto& i : _vert_buffers) { - ret.emplace_back(i.second); - } - return ret; -} - -RawVec VAOManager::attributeData(unsigned int i) { - if (i <= _vert_attrs.size()) { - throw std::out_of_range("No vertex attribute exists for specified index"); - } - VertexAttribute attr = _vert_attrs[i]; - BufferManagerPointer buffer = _vert_buffers[attr.ptr.buffer]; - RawVec data = buffer->data(); - unsigned int attr_size = attr.GLSLSize*GLSLTypeSize(attr.GLSLType); - RawVec ret((buffer->size()-attr.ptr.offset-attr_size)*attr_size/attr.ptr.stride); - int data_size = data.size(); - for (int i{0}; i < data_size; ++i) { - if (isIndexInVertexAttribute(i, attr)) { - ret[i] = data[i]; - } - } - return ret; -} - -RawVec VAOManager::attributeData(unsigned int i, const RawVec& new_data) { - if (i >= _vert_attrs.size()) { - throw std::out_of_range("No vertex attribute exists for specified index."); - } - VertexAttribute attr = _vert_attrs[i]; - BufferManagerPointer buffer = _vert_buffers[attr.ptr.buffer]; - unsigned int attr_size = attr.GLSLSize*GLSLTypeSize(attr.GLSLType); - unsigned int offset = attr.ptr.offset; - unsigned int num_verts = buffer->size() / vertSize(buffer->id()); - if (num_verts*attr_size != new_data.size()) { - // WHY HERE???? - THROW_VAO_ERROR( - "Input data size of " + std::to_string(new_data.size()) - + " does not match data size for requested vertex attribute of total size " + std::to_string(num_verts*attr_size) - + "." - ); - } - uint64_t pos = uint64_t(new_data.data()); - for (int i{0}; idata((void*)(pos+i*attr_size), offset+i*attr.ptr.stride, attr_size); - } - return RawVec(new_data); -} - -void VAOManager::bind() const { - glBindVertexArray(_id); - if (_elmt_buffer) { _elmt_buffer->bind(); } -} - -void VAOManager::unbind() const { - glBindVertexArray(0); - if (_elmt_buffer) { _elmt_buffer->unbind(); } -} - -void VAOManager::addVBO(BufferManagerPointer vert_buf) { - GLuint vert_id = vert_buf->id(); - if (_vert_buffers.find(vert_id) == _vert_buffers.end()) { - _vert_buffers[vert_buf->id()] = vert_buf; - } else { - THROW_VAO_ERROR("Attempting to add identical VBO id of " + std::to_string(vert_id) + "."); - } -} - -void VAOManager::changeEBO(BufferManagerPointer ebo) { - _elmt_buffer = ebo; -} - -VertexAttributeList VAOManager::addVertexAttributes(const VertexAttributeList& vert_attrs) { - VertexAttributeList curr_vas = _vert_attrs; - curr_vas.insert(curr_vas.end(), vert_attrs.begin(), vert_attrs.end()); - try { - throw checkValid(curr_vas); - } catch (VAOError vaoe) { - if (vaoe.error) { - THROW_VAO_ERROR(vaoe.what()); - } - } - _vert_attrs = curr_vas; - generate(); - return _vert_attrs; -} - -VertexAttributeList VAOManager::addVertexAttributes(VertexAttribute vert_attr) { - return addVertexAttributes({vert_attr}); -} - -VertexAttributeList VAOManager::generate() { - bind(); - unsigned int num_attrs = _vert_attrs.size(); - VertexAttribute* va; - for (int i = 0; i < num_attrs; ++i) { - va = &(_vert_attrs[i]); - _vert_buffers[va->ptr.buffer]->bind(); - glVertexAttribPointer( - i, - va->GLSLSize, - va->GLSLType, - va->GLSLNormalization, - va->ptr.stride, - (void*)va->ptr.offset - ); - glVertexAttribDivisor(i, va->ptr.divisor); - glEnableVertexAttribArray(i); - } - if (_elmt_buffer != nullptr) { - _elmt_buffer->bind(); - } - unbind(); - return _vert_attrs; -} - -VertexAttributeList VAOManager::generate(VertexAttributeList vert_attrs) { - try { - throw checkValid(vert_attrs); - } catch (VAOError vaoe) { - if (vaoe.error) { - THROW_VAO_ERROR(vaoe.what()); - } - } - _vert_attrs.swap(vert_attrs); - return generate(); -} - -VertexAttributeList VAOManager::changeLayout(unsigned int i, VertexAttributePointer vap) { - _vert_attrs[i].ptr = vap; - bind(); - const VertexAttribute* va = &(_vert_attrs[i]); - glDisableVertexAttribArray(i); - _vert_buffers[va->ptr.buffer]->bind(); - glVertexAttribPointer( - _id, - va->GLSLSize, - va->GLSLType, - va->GLSLNormalization, - va->ptr.stride, - (void*)va->ptr.offset - ); - glVertexAttribDivisor(i, va->ptr.divisor); - glEnableVertexAttribArray(i); - unbind(); - return _vert_attrs; -} - -VAOError VAOManager::checkValid(const VertexAttributeList& vert_attrs) { - GLuint va_id; - unsigned int num_attrs = vert_attrs.size(); - for (int i = 0; i < num_attrs; ++i) { - va_id = vert_attrs[i].ptr.buffer; - if (_vert_buffers.find(va_id) == _vert_buffers.cend()) { - return VAOError("Attempting to point to unknown VBO of id " + std::to_string(va_id) + - " at Vertex Attribute " + std::to_string(i) + "."); - } - if (vert_attrs[i].ptr.stride<0) { - return VAOError("Invalid stride value at Vertex Attribute " + std::to_string(i) + "."); - } - } - return VAOError(false); -} - -} // namespace NB diff --git a/engine/NBGraphics/src/VertexArray.cpp b/engine/NBGraphics/src/VertexArray.cpp new file mode 100644 index 0000000..01d3c63 --- /dev/null +++ b/engine/NBGraphics/src/VertexArray.cpp @@ -0,0 +1,222 @@ +#include "VertexArray.hpp" + +namespace nb { + +using VAOErrorCodes = VAOError::Codes; +const std::string VAOError::type = "nb::VAOError"; +const ErrorCodeMap VAOError::ErrorMessages = { + { VAOErrorCodes::UNDEFINED, "Error" }, + { VAOErrorCodes::INVALID_ATTRIBUTE, "Targeting invalid attribute"}, + { VAOErrorCodes::INVALID_VAO, "Targeting invalid VAO" } +}; + +VAO::VAO(const VertexAttributePointerList& attr_ptrs) { + attributes(attr_ptrs); +} + +VAO::VAO(VAO&& other) { + *this = std::move(other); +} + +VAO& VAO::operator=(VAO&& rhs) { + _id = rhs._id; + _attrs = rhs._attrs; + + rhs._id = 0; + rhs._attrs = {}; + + return *this; +} + +VertexAttributePointerList VAO::attributes() const { + return _attrs; +} + +VertexAttributePointerList VAO::attributes(const VertexAttributePointerList& attrs_) { + declare(); + disable(); + _attrs = attrs_; + bind(); + for (auto attr_ptr : attrs_) { + attr_ptr.buffer->bind(); + GLuint idx = attr_ptr.index; + glVertexAttribPointer( + idx, + attr_ptr.attribute.GLSLSize, + attr_ptr.attribute.GLSLType, + attr_ptr.attribute.GLSLNormalization, + attr_ptr.attribute.layout.stride, + (void*)attr_ptr.attribute.layout.offset + ); + glEnableVertexAttribArray(idx); + } + unbind(); + return _attrs; +} + +VertexAttributePointer VAO::attr(GLuint idx) const { + for (auto attr_ptr : _attrs) { + if (idx == attr_ptr.index) { + return attr_ptr; + } + } + THROW(BufferError(Codes::INVALID_ATTRIBUTE)); +} + +void VAO::enable() const { + if (_id) { + bind(); + for(auto attr_ptr : _attrs) { + glEnableVertexAttribArray(attr_ptr.index); + } + unbind(); + } +} + +void VAO::enable(GLuint idx) const { + if(_id) { + bind(); + glEnableVertexAttribArray(attr(idx).index); + unbind(); + } +} + +void VAO::disable() const { + if(_id) { + bind(); + for(auto attr_ptr : _attrs) { + glDisableVertexAttribArray(attr_ptr.index); + } + unbind(); + } +} + +void VAO::disable(GLuint idx) const { + if(_id) { + bind(); + glDisableVertexAttribArray(attr(idx).index); + unbind(); + } +} + +VertexGroup::VertexGroup(VertexGroup&& other) { + *this = std::move(other); +} + +VertexGroup& VertexGroup::operator=(VertexGroup&& rhs) { + _vertex_data = rhs._vertex_data; + _elmt_buf = std::move(rhs._elmt_buf); + _vao = std::move(rhs._vao); + + rhs._vertex_data = {}; + rhs._elmt_buf = ElementBuffer(); + rhs._vao = VAO(); + + return *this; +} + +size_t VertexGroup::buffer(VertexBuffer&& buf_) { + _vertex_data.emplace_back( + std::make_shared>(std::move(buf_)) + ); + VertexBuffer* buf_ptr = _vertex_data.back().get(); + VertexAttributePointerList attrs = _vao.attributes(); + GLuint idx = attrs.size(); + for (auto attr : buf_ptr->attributes) { + attrs.emplace_back( + VertexAttributePointer{attr, buf_ptr,idx} + ); + idx++; + } + _vao.attributes(attrs); + return _vertex_data.size(); +} + +VertexBuffer& VertexGroup::buffer(size_t idx) { + return *_vertex_data[idx]; +} + +std::vector>> VertexGroup::buffers() { + return _vertex_data; +} + +size_t VertexGroup::buffers(std::vector>&& bufs_) { + _vertex_data = {}; + for (auto& buf : bufs_) { + _vertex_data.emplace_back( + std::make_shared>(std::move(buf)) + ); + } + VertexAttributePointerList attr_ptrs; + GLuint idx = 0; + for (auto buf : _vertex_data) { + for (auto attr : buf->attributes) { + attr_ptrs.emplace_back( + VertexAttributePointer{attr, buf.get(), idx} + ); + idx++; + } + } + _vao.attributes(attr_ptrs); + return _vertex_data.size(); +} + +VertexBuffer&& VertexGroup::dropBuffer(size_t idx) { + if (idx >= _vertex_data.size()) { + THROW(BufferError(BufferError::Codes::INVALID_BUFFER)); + } + std::vector> tmp; + for (auto buf : _vertex_data) { + tmp.emplace_back(std::move(*buf)); + } + _vertex_data.clear(); + std::shared_ptr> ret_ptr = + std::make_shared>(std::move(tmp[idx])); + tmp.erase(tmp.begin()+idx); + buffers(std::move(tmp)); + return std::move(*ret_ptr); +} + +VertexAttributePointer VertexGroup::attribute(size_t idx_) const { + return _vao.attr(idx_); +} + +void VertexGroup::enableAttr(GLuint idx) { + bind(); + _vao.enable(idx); + unbind(); +} + +void VertexGroup::disableAttr(GLuint idx) { + bind(); + _vao.disable(idx); + unbind(); +} + +void VertexGroup::disableBuffer(size_t idx) { + auto buf_ptr = _vertex_data[idx].get(); + bind(); + for (auto attr : _vao.attributes()) { + if (attr.buffer == buf_ptr) { + _vao.disable(attr.index); + } + } + unbind(); +} + +void VertexGroup::enableBuffer(size_t idx) { + auto buf_ptr = _vertex_data[idx].get(); + bind(); + for (auto attr : _vao.attributes()) { + if (attr.buffer == buf_ptr) { + _vao.enable(attr.index); + } + } + unbind(); +} + +void VertexGroup::enable() { _vao.enable(); } + +void VertexGroup::disable() { _vao.disable(); } + +} // namespace nb diff --git a/engine/NBGraphics/tests/CMakeLists.txt b/engine/NBGraphics/tests/CMakeLists.txt new file mode 100644 index 0000000..e352a10 --- /dev/null +++ b/engine/NBGraphics/tests/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.26.0) + +if (NB_BUILD_TESTS) + enable_testing() + include(GoogleTest) + add_executable(TestWindow + ./TestWindow.cpp + ) + target_link_libraries(TestWindow + NBCore + NBGraphics + GTest::gtest_main + ) + gtest_discover_tests(TestWindow) + +endif() \ No newline at end of file diff --git a/engine/NBGraphics/tests/TestWindow.cpp b/engine/NBGraphics/tests/TestWindow.cpp new file mode 100644 index 0000000..d7df069 --- /dev/null +++ b/engine/NBGraphics/tests/TestWindow.cpp @@ -0,0 +1,6 @@ +#include + +int main() { + + return 0; +} \ No newline at end of file -- 2.43.0 From 8a050525163b808dc72dd5dfdc145f414c9e5fdd Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Mon, 8 Jun 2026 03:37:18 -0500 Subject: [PATCH 13/18] Made buildable now --- engine/NBGraphics/Buffers.hpp | 2 +- engine/NBGraphics/VertexArray.hpp | 9 ++++++--- engine/NBGraphics/src/VertexArray.cpp | 15 +++++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/engine/NBGraphics/Buffers.hpp b/engine/NBGraphics/Buffers.hpp index 4df38f3..7132a6c 100644 --- a/engine/NBGraphics/Buffers.hpp +++ b/engine/NBGraphics/Buffers.hpp @@ -138,7 +138,7 @@ class Buffer : public OpenGLObject { _usage = usage_; } virtual void data(const ByteVector& data_, GLenum usage_=GL_STATIC_DRAW) { - data(Target, data_.size(), data_.data(), usage_); + data(data_.data(), data_.size(), usage_); } virtual void subdata(void* data_, GLsizeiptr size_, GLintptr offset_=0) { diff --git a/engine/NBGraphics/VertexArray.hpp b/engine/NBGraphics/VertexArray.hpp index 30afe3a..b092e6c 100644 --- a/engine/NBGraphics/VertexArray.hpp +++ b/engine/NBGraphics/VertexArray.hpp @@ -51,16 +51,19 @@ class VAOError : public Error { template class VertexBuffer : public ArrayBuffer{ - using Base = ArrayBuffer; + using Base = ArrayBuffer; public: template - VertexBuffer(const VertexAttributeList& vas, Args... args) + VertexBuffer(const VertexAttributeList& vas={}, Args... args) : attributes(vas) { if (sizeof...(Args)) { data(args...); } } + VertexBuffer(VertexBuffer&& rhs) + : attributes(rhs.attributes), Base(std::move(rhs)){} + using Base::Target; const VertexAttributeList attributes; @@ -104,7 +107,7 @@ class VAO : public OpenGLObject { if(_id) { glBindVertexArray(_id); } else { - THROW(Codes::INVALID_VAO); + THROW(VAOError(Codes::INVALID_VAO)); } } virtual void unbind() const override { glBindVertexArray(0); } diff --git a/engine/NBGraphics/src/VertexArray.cpp b/engine/NBGraphics/src/VertexArray.cpp index 01d3c63..1914cf2 100644 --- a/engine/NBGraphics/src/VertexArray.cpp +++ b/engine/NBGraphics/src/VertexArray.cpp @@ -141,7 +141,7 @@ std::vector>> VertexGroup::buffers() { } size_t VertexGroup::buffers(std::vector>&& bufs_) { - _vertex_data = {}; + _vertex_data.clear(); for (auto& buf : bufs_) { _vertex_data.emplace_back( std::make_shared>(std::move(buf)) @@ -166,13 +166,16 @@ VertexBuffer&& VertexGroup::dropBuffer(size_t idx) { THROW(BufferError(BufferError::Codes::INVALID_BUFFER)); } std::vector> tmp; + std::shared_ptr> ret_ptr; + size_t i = 0; for (auto buf : _vertex_data) { - tmp.emplace_back(std::move(*buf)); + if (i == idx) { + ret_ptr = std::make_shared>(std::move(tmp[idx])); + } else { + tmp.emplace_back(std::move(*buf)); + } + i++; } - _vertex_data.clear(); - std::shared_ptr> ret_ptr = - std::make_shared>(std::move(tmp[idx])); - tmp.erase(tmp.begin()+idx); buffers(std::move(tmp)); return std::move(*ret_ptr); } -- 2.43.0 From 2a2547f216581766b392de5c3b43b93b6fc5487e Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Wed, 10 Jun 2026 19:43:35 -0500 Subject: [PATCH 14/18] Make VertexAttributePointer store index instead of buffer pointer --- engine/NBGraphics/VertexArray.hpp | 12 +++++------- engine/NBGraphics/src/VertexArray.cpp | 14 +++++++------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/engine/NBGraphics/VertexArray.hpp b/engine/NBGraphics/VertexArray.hpp index b092e6c..be13f52 100644 --- a/engine/NBGraphics/VertexArray.hpp +++ b/engine/NBGraphics/VertexArray.hpp @@ -25,7 +25,11 @@ struct VertexAttribute { VertexAttributeLayout layout; }; -struct VertexAttributePointer; +struct VertexAttributePointer { + VertexAttribute attribute; + GLuint buffer; + GLuint index; +}; static bool isIndexInVertexAttribute(int i, const VertexAttribute& va) { if ((i -= va.layout.offset) < 0) { return false; } @@ -85,12 +89,6 @@ class VertexBuffer }; -struct VertexAttributePointer { - VertexAttribute attribute; - VertexBuffer* buffer; - GLuint index; -}; - class VAO : public OpenGLObject { using Base = OpenGLObject; using Codes = VAOError::Codes; diff --git a/engine/NBGraphics/src/VertexArray.cpp b/engine/NBGraphics/src/VertexArray.cpp index 1914cf2..b84eebf 100644 --- a/engine/NBGraphics/src/VertexArray.cpp +++ b/engine/NBGraphics/src/VertexArray.cpp @@ -38,7 +38,7 @@ VertexAttributePointerList VAO::attributes(const VertexAttributePointerList& att _attrs = attrs_; bind(); for (auto attr_ptr : attrs_) { - attr_ptr.buffer->bind(); + glBindBuffer(GL_ARRAY_BUFFER, attr_ptr.buffer); GLuint idx = attr_ptr.index; glVertexAttribPointer( idx, @@ -124,7 +124,7 @@ size_t VertexGroup::buffer(VertexBuffer&& buf_) { GLuint idx = attrs.size(); for (auto attr : buf_ptr->attributes) { attrs.emplace_back( - VertexAttributePointer{attr, buf_ptr,idx} + VertexAttributePointer{attr, buf_ptr->id(),idx} ); idx++; } @@ -152,7 +152,7 @@ size_t VertexGroup::buffers(std::vector>&& bufs_) { for (auto buf : _vertex_data) { for (auto attr : buf->attributes) { attr_ptrs.emplace_back( - VertexAttributePointer{attr, buf.get(), idx} + VertexAttributePointer{attr, buf->id(), idx} ); idx++; } @@ -197,10 +197,10 @@ void VertexGroup::disableAttr(GLuint idx) { } void VertexGroup::disableBuffer(size_t idx) { - auto buf_ptr = _vertex_data[idx].get(); + auto buf_idx = _vertex_data[idx]->id(); bind(); for (auto attr : _vao.attributes()) { - if (attr.buffer == buf_ptr) { + if (attr.buffer == buf_idx) { _vao.disable(attr.index); } } @@ -208,10 +208,10 @@ void VertexGroup::disableBuffer(size_t idx) { } void VertexGroup::enableBuffer(size_t idx) { - auto buf_ptr = _vertex_data[idx].get(); + auto buf_idx = _vertex_data[idx]->id(); bind(); for (auto attr : _vao.attributes()) { - if (attr.buffer == buf_ptr) { + if (attr.buffer == buf_idx) { _vao.enable(attr.index); } } -- 2.43.0 From cda9950d33f6aaadaa912310d2d39b0cf976e86e Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Thu, 11 Jun 2026 04:21:53 -0500 Subject: [PATCH 15/18] Mild updates to Window and other pieces to match the rest --- engine/NBGraphics/GLLoad.hpp | 26 ------------------- engine/NBGraphics/Window.hpp | 30 +++++++++++++++++++--- engine/NBGraphics/src/Window.cpp | 35 ++++++++++++++++++-------- engine/NBGraphics/tests/CMakeLists.txt | 4 +-- engine/NBGraphics/tests/TestWindow.cpp | 14 ++++++++++- 5 files changed, 66 insertions(+), 43 deletions(-) diff --git a/engine/NBGraphics/GLLoad.hpp b/engine/NBGraphics/GLLoad.hpp index 7989fb3..8158ecd 100644 --- a/engine/NBGraphics/GLLoad.hpp +++ b/engine/NBGraphics/GLLoad.hpp @@ -5,30 +5,4 @@ #include #include -#include - -namespace NB { - -static unsigned int __NB_GL_DEBUG_ERROR_CODE__; - -static std::string formatDebugString(const std::string& msg, const std::string& file="", int line=-1) { - std::string ret = ""; - if (file != "") { - ret += "In file " + file; - if (line >= 0) { - ret += " at line " + std::to_string(line); - } - ret += ":\n\t"; - } - return ret + msg; -} - -} - -#define NB_GL_DEBUG_THROW(cmd, when) while(NB::__NB_GL_DEBUG_ERROR_CODE__=glGetError()){\ - std::cout << "[GL ERROR]: " << NB::__NB_GL_DEBUG_ERROR_CODE__;\ - std::cout << " " << when << " " << cmd << "\n";\ -} -#define NB_GL_DEBUG(cmd) NB_GL_DEBUG_THROW(#cmd, "before"); cmd; NB_GL_DEBUG_THROW(#cmd, "after"); - #endif \ No newline at end of file diff --git a/engine/NBGraphics/Window.hpp b/engine/NBGraphics/Window.hpp index 88e84df..36e1d4b 100644 --- a/engine/NBGraphics/Window.hpp +++ b/engine/NBGraphics/Window.hpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace nb { @@ -18,9 +19,32 @@ public: GLError(const std::string&); }; -class WindowError : public std::runtime_error { -public: - WindowError(const std::string&); +class OpenGLError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, INIT_FAILED, GLFW_INTIALIZED, GLAD_FAILED + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; + +class WindowError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, INITIALIZED_WINDOW, NO_GLFW, INIT_FAILED + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; }; class Window { diff --git a/engine/NBGraphics/src/Window.cpp b/engine/NBGraphics/src/Window.cpp index adceaf7..5229af1 100644 --- a/engine/NBGraphics/src/Window.cpp +++ b/engine/NBGraphics/src/Window.cpp @@ -16,9 +16,25 @@ static std::map defailt_window_hints = { #endif }; -GLError::GLError(const std::string& msg) : std::runtime_error(msg) {} +using OpenGLErrorCodes = OpenGLError::Codes; +const std::string OpenGLError::type = "nb::OpenGLError"; +const ErrorCodeMap OpenGLError::ErrorMessages = { + {OpenGLErrorCodes::UNDEFINED, "Error"}, + {OpenGLErrorCodes::INIT_FAILED, "GLFW initialization failed"}, + {OpenGLErrorCodes::GLFW_INTIALIZED, "GLFW has already been initialized"}, + {OpenGLErrorCodes::GLAD_FAILED, "GLAD initialization failed"} +}; -WindowError::WindowError(const std::string &msg) : std::runtime_error(msg) {} +using WindowErrorCodes = WindowError::Codes; +const std::string WindowError::type = "nb::WindowError"; +const ErrorCodeMap WindowError::ErrorMessages = { + {WindowErrorCodes::UNDEFINED, "Error"}, + {WindowErrorCodes::INITIALIZED_WINDOW, "Window already initialized"}, + {WindowErrorCodes::NO_GLFW, "GLFW has not been initialized"}, + {WindowErrorCodes::INIT_FAILED, "Could not intialized window"} +}; + +GLError::GLError(const std::string& msg) : std::runtime_error(msg) {} int Window::getGLFWHint(int hint_key) { if (GLFWHints.find(hint_key) == GLFWHints.end()) { @@ -30,7 +46,7 @@ int Window::getGLFWHint(int hint_key) { int Window::setGLFWHint(int hint_key, int hint_val) { if (Window::_glfw_init) { - throw GLError("Cannot set GLFW hint after window is initialized."); + THROW(OpenGLError(OpenGLErrorCodes::GLFW_INTIALIZED)); } else { GLFWHints[hint_key] = hint_val; } @@ -60,7 +76,7 @@ Window::Window(const uint16_t x, const uint16_t y, const char* initName, GLFWmon Window::_glfw_init = true; } else { if (Window::StrictInitialization) { - throw GLError("Failed to load GLFW with glfwInit()="+std::to_string(glfwResponse)+"."); + THROW(OpenGLError(OpenGLErrorCodes::INIT_FAILED)); } } } @@ -103,7 +119,7 @@ int Window::getWindowHint(int hint_key) const { int Window::setWindowHint(int hint_key, int hint_val) { if (_init) { - throw WindowError("Cannot set window hint after window is initialized."); + THROW(WindowError(WindowErrorCodes::INITIALIZED_WINDOW)); } else { windowHints[hint_key] = hint_val; } @@ -112,7 +128,7 @@ int Window::setWindowHint(int hint_key, int hint_val) { int Window::init() { if (!_glfw_init) { - throw GLError("GLFW has not been initialized."); + THROW(WindowError(WindowErrorCodes::NO_GLFW)); } for (const auto& hint : windowHints) { glfwWindowHint(hint.first, hint.second); @@ -123,7 +139,7 @@ int Window::init() { Window::WindowContexts.erase(window); if (Window::WindowContexts.size()==0 && Window::_glfw_init) { glfwTerminate(); } if (Window::StrictInitialization) { - throw WindowError("Could not create window in glfwCreateWindow()."); + THROW(WindowError(WindowErrorCodes::INIT_FAILED)); } } glfwMakeContextCurrent(window); @@ -133,10 +149,7 @@ int Window::init() { if (!gladResponse) { Window::checkKillGLFW(); if (Window::StrictInitialization) { - throw GLError("Failed to load GLAD with \ - gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)="+\ - std::to_string(gladResponse)+"." - ); + THROW(OpenGLError(OpenGLErrorCodes::GLAD_FAILED)); } } diff --git a/engine/NBGraphics/tests/CMakeLists.txt b/engine/NBGraphics/tests/CMakeLists.txt index e352a10..62ecefc 100644 --- a/engine/NBGraphics/tests/CMakeLists.txt +++ b/engine/NBGraphics/tests/CMakeLists.txt @@ -9,8 +9,8 @@ if (NB_BUILD_TESTS) target_link_libraries(TestWindow NBCore NBGraphics - GTest::gtest_main +# GTest::gtest_main ) - gtest_discover_tests(TestWindow) +# gtest_discover_tests(TestWindow) endif() \ No newline at end of file diff --git a/engine/NBGraphics/tests/TestWindow.cpp b/engine/NBGraphics/tests/TestWindow.cpp index d7df069..03a7c0e 100644 --- a/engine/NBGraphics/tests/TestWindow.cpp +++ b/engine/NBGraphics/tests/TestWindow.cpp @@ -1,6 +1,18 @@ -#include +#include "GLLoad.hpp" +// #define _NB_AUTOLOG +#include "VertexArray.hpp" +#include "Window.hpp" + int main() { + nb::logger.log("Howdy!"); + nb::Window window(200, 200, "Hello!"); + window.setWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + window.setWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + window.init(); + + GLFWwindow* window_ptr = window.getWindow(); + while(!glfwWindowShouldClose(window_ptr)) {} return 0; } \ No newline at end of file -- 2.43.0 From 521483f4e054750af764575c7b228223b978da2d Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 26 Jun 2026 02:42:16 -0500 Subject: [PATCH 16/18] Added vertex buffers/data handling and shader/program handling --- engine/NBGraphics/Buffers.hpp | 93 +-- engine/NBGraphics/CMakeLists.txt | 3 +- engine/NBGraphics/OGLObjects.hpp | 6 +- engine/NBGraphics/ProgramPipeline.hpp | 123 ++++ engine/NBGraphics/VertexArray.hpp | 96 +-- engine/NBGraphics/Window.hpp | 5 - engine/NBGraphics/shader.hpp | 193 ------ engine/NBGraphics/src/Buffers.cpp | 7 +- engine/NBGraphics/src/ProgramPipeline.cpp | 75 +++ engine/NBGraphics/src/VertexArray.cpp | 98 +-- engine/NBGraphics/src/Window.cpp | 2 - engine/NBGraphics/src/shader.cpp | 742 ---------------------- engine/NBGraphics/tests/CMakeLists.txt | 2 - engine/NBGraphics/tests/TestWindow.cpp | 50 +- 14 files changed, 386 insertions(+), 1109 deletions(-) create mode 100644 engine/NBGraphics/ProgramPipeline.hpp delete mode 100644 engine/NBGraphics/shader.hpp create mode 100644 engine/NBGraphics/src/ProgramPipeline.cpp delete mode 100644 engine/NBGraphics/src/shader.cpp diff --git a/engine/NBGraphics/Buffers.hpp b/engine/NBGraphics/Buffers.hpp index 7132a6c..0e08b99 100644 --- a/engine/NBGraphics/Buffers.hpp +++ b/engine/NBGraphics/Buffers.hpp @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -16,69 +15,20 @@ namespace nb { -static uint8_t GLSLTypeSize(GLenum type) { - switch(type) { - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_HALF_FLOAT: - return 2; - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - return 4; - break; - case GL_DOUBLE: - return 8; - break; - default: - return 1; - break; - } -} - -template -ByteVector vectorToRaw(const std::vector& vec) { - unsigned int num_bytes = vec.size() * sizeof(T); - ByteVector ret(num_bytes); - memcpy(ret.data(), vec.data(), num_bytes); - return ret; -} - -template -ByteVector concatVectorsToRaw(const std::vector& vec1, const std::vector& vec2) { - ByteVector vec1_raw = vectorToRaw(vec1); - ByteVector vec2_raw = vectorToRaw(vec2); - unsigned int vec1_raw_size = vec1_raw.size(); - unsigned int vec2_raw_size = vec2_raw.size(); - ByteVector ret(vec1_raw_size + vec2_raw_size); - memcpy(ret.data(), vec1_raw.data(), vec1_raw_size); - memcpy(ret.data() + vec1_raw_size, vec2_raw.data(), vec2_raw_size); - return ret; -} - -template -std::vector rawToVector(const ByteVector& vec) { - if (vec.size() % sizeof(T) != 0) { - THROW(std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">.")); - } - unsigned int num_elmts = vec.size() / sizeof(T); - std::vector ret(num_elmts); - memcpy(ret.data(), vec.data(), vec.size()); - - return ret; -} +extern const std::unordered_map BufferTypes; class BufferError : public Error { + protected: using Base = Error; - - public: using Base::Base; - - enum Codes : unsigned int { - UNDEFINED, DATA_OVERFLOW, INVALID_BUFFER, HANDLE_OVERWRITE - }; + public: + enum Codes : unsigned int { + UNDEFINED, + DATA_OVERFLOW, + INVALID_BUFFER, + HANDLE_OVERWRITE, + }; static const std::string type; static const ErrorCodeMap ErrorMessages; }; @@ -89,13 +39,25 @@ class Buffer : public OpenGLObject { public: using OpenGLObject::OpenGLObject; - Buffer() = default; Buffer(Buffer&& other) { *this = std::move(other); } Buffer& operator=(Buffer&& rhs) { - if (_id) { THROW(BufferError(Codes::HANDLE_OVERWRITE)); } + auto targ_name = BufferTypes.at(Target); + if (Target != rhs.Target) { + THROW(BufferError( + Codes::INVALID_BUFFER, + "w/ ("+targ_name+") := ("+BufferTypes.at(rhs.Target)+")" + )); + } + //nb::logger.log(std::to_string(_id) + ":=" + std::to_string(rhs._id)); + if (_id) { + THROW(BufferError( + Codes::HANDLE_OVERWRITE, + "w/ BufferType = " + targ_name + )); + } _id = rhs._id; _usage = rhs._usage; _size = rhs._size; @@ -109,8 +71,12 @@ class Buffer : public OpenGLObject { virtual void bind() const override { if (_id) { glBindBuffer(Target, _id); + } else { + THROW(BufferError( + Codes::INVALID_BUFFER, + "w/ BufferType " + BufferTypes.at(Target) + )); } - THROW(BufferError(Codes::INVALID_BUFFER)); } virtual void unbind() const override { glBindBuffer(Target, 0); } virtual GLenum usage() const { return _usage; } @@ -240,13 +206,14 @@ class ArrayBuffer using BufferType = ImmutableBuffer>; using BufferType::BufferType; + public: using Base::Target; }; template -class ElementBuffer : public virtual Buffer> { +class ElementBuffer : public Buffer> { using Base = Buffer>; using BufferType = Base; diff --git a/engine/NBGraphics/CMakeLists.txt b/engine/NBGraphics/CMakeLists.txt index f799880..5a94b3f 100644 --- a/engine/NBGraphics/CMakeLists.txt +++ b/engine/NBGraphics/CMakeLists.txt @@ -10,6 +10,7 @@ set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) toAbsolutePath(NB_GRAPHICS_SOURCE ./src/Buffers.cpp ./src/OGLObjects.cpp + ./src/ProgramPipeline.cpp ./src/Textures.cpp ./src/VertexArray.cpp ./src/Window.cpp @@ -21,7 +22,7 @@ toAbsolutePath(NB_GRAPHICS_INCLUDE ./Draw.hpp ./GLLoad.hpp ./OGLObjects.hpp - ./shader.hpp + ./ProgramPipeline.hpp ./Textures.hpp ./VertexArray.hpp ./Window.hpp diff --git a/engine/NBGraphics/OGLObjects.hpp b/engine/NBGraphics/OGLObjects.hpp index 64cd302..bb0dc8a 100644 --- a/engine/NBGraphics/OGLObjects.hpp +++ b/engine/NBGraphics/OGLObjects.hpp @@ -26,7 +26,7 @@ class OpenGLObject { public: OpenGLObject(const OpenGLObject&) = delete; OpenGLObject& operator=(const OpenGLObject&) = delete; - ~OpenGLObject() { remove(); } + virtual ~OpenGLObject() {}; virtual void bind() const = 0; virtual void unbind() const = 0; @@ -36,9 +36,9 @@ class OpenGLObject { OpenGLObject() = default; virtual GLuint declare() = 0; - virtual void remove() { this->remove(); }; + virtual void remove() = 0; - GLuint _id; + GLuint _id = 0; }; } // namespace nb diff --git a/engine/NBGraphics/ProgramPipeline.hpp b/engine/NBGraphics/ProgramPipeline.hpp new file mode 100644 index 0000000..fce51a7 --- /dev/null +++ b/engine/NBGraphics/ProgramPipeline.hpp @@ -0,0 +1,123 @@ +#pragma once +#ifndef _NB_SHADER +#define _NB_SHADER + +#include "GLLoad.hpp" + +#include + +#include +#include + +#include "OGLObjects.hpp" + +namespace nb { + +class ShaderError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; + +class ProgramError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, LINKING_ERROR + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; + +enum OpenGLProfiles { + Core, + Compatibility, + ES +}; + +class Shader : public OpenGLObject { + using Base = OpenGLObject; + + public: + using Base::Base; + using Base::id; + Shader(GLenum, const std::string&); + Shader(Shader&&); + Shader& operator=(Shader&&) = delete; + ~Shader() { remove(); } + operator bool(); + virtual void bind() const override { /* TODO: Some warning of some kind perhaps*/ } + virtual void unbind() const override { /* TODO: Some warning of some kind perhaps*/ } + GLint status(GLenum) const; + std::string log() const; + const GLenum target; + friend Base; + + protected: + using Base::_id; + GLint _success; + virtual GLuint declare() override { + if (!_id) { + _id = _id = glCreateShader(target); + } + return _id; + } + + virtual void remove() override { + if (_id) { + glDeleteShader(_id); + } + } + +}; + +class Program : public OpenGLObject { + using Base = OpenGLObject; + + public: + using Base::Base; + using Base::id; + Program(SharedVector); + Program(Program&&); + Program& operator=(Program&&) = delete; + operator bool(); + ~Program() { remove(); } + virtual void bind() const override { + glUseProgram(_id); + } + virtual void unbind() const override { /* TODO: Some warning of some kind perhaps*/ } + GLint status(GLenum) const; + std::string log() const; + friend Base; + + protected: + using Base::_id; + GLint _success; + virtual GLuint declare() override { + if (!_id) { + _id = glCreateProgram(); + } + return _id; + } + virtual void remove() override { + if (_id) { + glDeleteProgram(_id); + } + } + +}; + +} +#endif \ No newline at end of file diff --git a/engine/NBGraphics/VertexArray.hpp b/engine/NBGraphics/VertexArray.hpp index be13f52..2f97c28 100644 --- a/engine/NBGraphics/VertexArray.hpp +++ b/engine/NBGraphics/VertexArray.hpp @@ -12,6 +12,27 @@ namespace nb { +static uint8_t GLSLTypeSize(GLenum type) { + switch(type) { + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_HALF_FLOAT: + return 2; + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return 4; + break; + case GL_DOUBLE: + return 8; + break; + default: + return 1; + break; + } +} + struct VertexAttributeLayout { int32_t offset = 0; GLsizei stride = 0; @@ -53,42 +74,6 @@ class VAOError : public Error { static const ErrorCodeMap ErrorMessages; }; -template -class VertexBuffer : public ArrayBuffer{ - using Base = ArrayBuffer; - - public: - template - VertexBuffer(const VertexAttributeList& vas={}, Args... args) - : attributes(vas) { - if (sizeof...(Args)) { - data(args...); - } - } - VertexBuffer(VertexBuffer&& rhs) - : attributes(rhs.attributes), Base(std::move(rhs)){} - - - using Base::Target; - const VertexAttributeList attributes; - - protected: - using Base::_usage; - -}; - -template <> -class VertexBuffer -: public virtual VertexBuffer, public virtual ImmutableBuffer> { - using Base = ArrayBuffer; - using BufferType = ImmutableBuffer>; - using BufferType::BufferType; - - public: - using Base::Target; - -}; - class VAO : public OpenGLObject { using Base = OpenGLObject; using Codes = VAOError::Codes; @@ -139,25 +124,40 @@ class VAO : public OpenGLObject { }; +using VBO = ArrayBuffer; +using VertBufVec = SharedVector; +using EBO = ElementBuffer; + +struct VertexData { + std::shared_ptr vbo; + VertexAttributeList attrs; +}; + +using VertexDataVec = std::vector; + class VertexGroup { public: VertexGroup(VertexGroup&&); VertexGroup& operator=(VertexGroup&&); + + VertexGroup(const VertexData&); + VertexGroup(const VertexDataVec&); + VertexGroup(const ByteVector&, const VertexAttributeList&); void bind() const { - _elmt_buf.bind(); - _vao.bind(); + _ebo->bind(); + _vao->bind(); } void unbind() const { - _vao.bind(); - _elmt_buf.unbind(); + _vao->unbind(); + _ebo->unbind(); } - VertexBuffer& buffer(size_t); - size_t buffer(VertexBuffer&&); - std::vector>> buffers(); - size_t buffers(std::vector>&&); - VertexBuffer&& dropBuffer(size_t); + VertexDataVec getBuffers(); + VertexData getBuffers(size_t); + size_t setBuffers(const VertexDataVec&); + size_t addBuffer(const VertexData&); + VertexData dropBuffer(size_t); VertexAttributePointer attribute(size_t) const; void enableAttr(GLuint); @@ -168,9 +168,9 @@ class VertexGroup { void disable(); protected: - std::vector>> _vertex_data; - ElementBuffer _elmt_buf; - VAO _vao; + VertexDataVec _vertex_data; + std::shared_ptr _ebo; + std::shared_ptr _vao; }; } // namespace nb diff --git a/engine/NBGraphics/Window.hpp b/engine/NBGraphics/Window.hpp index 36e1d4b..b72cfa6 100644 --- a/engine/NBGraphics/Window.hpp +++ b/engine/NBGraphics/Window.hpp @@ -14,11 +14,6 @@ namespace nb { -class GLError : public std::runtime_error { -public: - GLError(const std::string&); -}; - class OpenGLError : public Error { using Base = Error; diff --git a/engine/NBGraphics/shader.hpp b/engine/NBGraphics/shader.hpp deleted file mode 100644 index ca92fe3..0000000 --- a/engine/NBGraphics/shader.hpp +++ /dev/null @@ -1,193 +0,0 @@ -#pragma once -#ifndef _NB_SHADER -#define _NB_SHADER - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// #define _PREPROC_FUNC_PARAMS_ (const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&, std::vector&) - -namespace NB { - -class ShaderPreprocessorError : public std::runtime_error { -public: - enum Codes : unsigned char { - NONE, - FILE_NOT_FOUND, - BUILTIN_NOT_FOUND, - CUSTOM, - UNDEFINED - }; - - const Codes code; - - ShaderPreprocessorError(const std::string&, const std::string& file="", int line=-1); - ShaderPreprocessorError(Codes, const std::string& arg="", const std::string& file="", int line=-1); - -protected: - static std::string errorCodeParser(Codes, const std::string& arg=""); -}; - -class ShaderError : public std::runtime_error { -public: - ShaderError(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1); - -protected: - std::string formatString(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1); -}; - -struct File { - // typedef std::tuple FilePath; - struct FilePath { - std::string dir; - std::string basename; - std::string ext; - }; - FilePath path; - std::stringstream src; - std::map> include_map; - - File() {} - File(const File& rhs) { *this = rhs; } - - File& operator=(const File& rhs) { - path = rhs.path; - src.str(""); - src << rhs.src.rdbuf(); - include_map = rhs.include_map; - return *this; - } -}; - -// File::FilePath get_file_path(std::string); - -class ShaderPreprocessor; - -enum OpenGLProfiles { - Core, - Compatibility, - ES -}; - -struct ShaderUnit { - GLenum type = 0x0; - File file; - std::string preprocSource; - std::map defines; - short vMajor=0, vMinor=0; - OpenGLProfiles profile = Core; -}; - -class ShaderPreprocessor; - -class ShaderProgram { - friend ShaderPreprocessor; -public: - ShaderProgram() {} - ShaderProgram(const ShaderProgram& rhs) = delete; - ShaderProgram(ShaderProgram&& rhs); - - ~ShaderProgram(); - - ShaderProgram& operator=(const ShaderProgram& rhs) = delete; - ShaderProgram& operator=(ShaderProgram&& rhs); - - std::vector getShaders() const; - ShaderUnit getShaders(unsigned int) const; - void use() const; - unsigned int id() const; - - void setBool(const std::string& name, bool value) const; - void setInt(const std::string& name, int value) const; - void setUnsigned(const std::string& name, int value) const; - void setFloat(const std::string& name, float value) const; - void setMat4(const std::string& name, glm::mat4& value) const; - - static ShaderProgram CreateShaderProgram(std::vector&); - -private: - ShaderProgram(std::vector& shaders) : _shader_units(shaders){} - - std::vector _shader_units; - unsigned int _id; -}; - -class ShaderPreprocessor { -public: - typedef ShaderPreprocessorError::Codes Codes; - - enum TokenType { - TK, - DR, - WS, - NL, - LC, - BC - }; - static std::string TokenName(const TokenType&); - - std::map AcceptedExtensions = { - {".frag", GL_FRAGMENT_SHADER}, - {".fs", GL_FRAGMENT_SHADER}, - {".vert", GL_VERTEX_SHADER}, - {".vs", GL_VERTEX_SHADER}, - {".tess", 0x0}, - {".geom", GL_GEOMETRY_SHADER}, - {".comp", 0x0}, - {".shad", 0x0}, - {".glsl", 0x0} - }; - std::map AcceptedProfiles { - {"core", Core}, - {"compatibility", Compatibility}, - {"es", ES} - }; - std::vector Directories; - std::map BuiltIns; - - ShaderPreprocessor(); - - - File load(const std::string, bool builtin_first=false) const; - ShaderUnit& preprocess(const std::string&, ShaderUnit&) const; - ShaderUnit preprocess(File, GLenum shader_type=0x0) const; - ShaderUnit preprocess(const std::string&, GLenum shader_type=0x0) const; - ShaderProgram ReloadFromFile(const ShaderProgram& rhs) const; - ShaderProgram CreateShaderProgram(std::vector) const; - -private: - typedef std::pair Token; - typedef std::vector StringVec; - - inline bool directive_dispatch(ShaderUnit&, const std::string&) const; - inline std::vector tokenize(const std::string&) const; - - inline bool preprocessor_include(ShaderUnit&, const StringVec&, const std::string&) const; - inline bool preprocessor_version(ShaderUnit&, const StringVec&, const std::string&) const; - inline bool preprocessor_define(ShaderUnit&, const StringVec&, const std::string&) const; - // inline bool preprocessor_uniform(ShaderUnit&, const std::string&, const std::string&) const; - - File loadFromBase(const std::string, const std::string base="") const; - File loadFromDirectories(const std::string) const; - File loadFromBuiltIn(const std::string) const; - File load_BuiltInFirst(const std::string) const; - File load_FilesFirst(const std::string) const; -}; - -} -#endif \ No newline at end of file diff --git a/engine/NBGraphics/src/Buffers.cpp b/engine/NBGraphics/src/Buffers.cpp index 3f80a45..99379da 100644 --- a/engine/NBGraphics/src/Buffers.cpp +++ b/engine/NBGraphics/src/Buffers.cpp @@ -2,13 +2,18 @@ namespace nb { +const std::unordered_map BufferTypes({ + {GL_ARRAY_BUFFER, "GL_ARRAY_BUFFER"}, + {GL_ELEMENT_ARRAY_BUFFER, "GL_ELEMENT_BUFFER"} +}); + using BufferErrorCodes = BufferError::Codes; const std::string BufferError::type = "nb::BufferError"; const ErrorCodeMap BufferError::ErrorMessages = { { BufferErrorCodes::UNDEFINED, "Error" }, { BufferErrorCodes::DATA_OVERFLOW, "Attempting buffer overflow" }, { BufferErrorCodes::INVALID_BUFFER, "Attempting operation on invalid buffer" }, - {BufferErrorCodes::HANDLE_OVERWRITE, "Attempting to overwrite active buffer"} + { BufferErrorCodes::HANDLE_OVERWRITE, "Attempting to overwrite active buffer"} }; diff --git a/engine/NBGraphics/src/ProgramPipeline.cpp b/engine/NBGraphics/src/ProgramPipeline.cpp new file mode 100644 index 0000000..d4cea76 --- /dev/null +++ b/engine/NBGraphics/src/ProgramPipeline.cpp @@ -0,0 +1,75 @@ +#include "ProgramPipeline.hpp" + +namespace nb{ + +using ShaderErrCodes = ShaderError::Codes; +const std::string ShaderError::type = "nb::ShaderError"; +const ErrorCodeMap ShaderError::ErrorMessages = { + {ShaderErrCodes::UNDEFINED, "Error"} +}; + +using ProgramErrCodes = ProgramError::Codes; +const std::string ProgramError::type = "nb::ProgramError"; +const ErrorCodeMap ProgramError::ErrorMessages = { + {ProgramErrCodes::UNDEFINED, "Error"}, + {ProgramErrCodes::LINKING_ERROR, "Linker error"} +}; + +Shader::Shader(GLenum target_, const std::string& source_) : target(target_) { + declare(); + _success = status(GL_COMPILE_STATUS); +} + +Shader::Shader(Shader&& cpy) : target(cpy.target) { + _id = cpy._id; +} + +Shader::operator bool() { return _success; } + +GLint Shader::status(GLenum parameter) const { + GLint param = 0; + glGetShaderiv(_id, parameter, ¶m); + return param; +} + +std::string Shader::log() const { + GLint logsize = status(GL_INFO_LOG_LENGTH); + char* log_ = new char[logsize]; + glGetShaderInfoLog(_id, logsize, NULL, log_); + std::string ret(log_, logsize); + delete[] log_; + return ret; +} + +Program::Program(SharedVector shaders_) { + declare(); + for (auto shad_ptr : shaders_) { + glAttachShader(_id, shad_ptr->id()); + } + glLinkProgram(_id); + _success = status(GL_LINK_STATUS); + if (!_success) { + WARN(log(), 0x01); + } +} + +Program::operator bool() { return _success; } + +GLint Program::status(GLenum parameter) const { + GLint param = 0; + glGetProgramiv(_id, parameter, ¶m); + return param; +} + +std::string Program::log() const { + GLint logsize = status(GL_INFO_LOG_LENGTH); + char* log_ = new char[logsize]; + glGetProgramInfoLog(_id, logsize, NULL, log_); + std::string ret(log_, logsize); + delete[] log_; + return ret; +} + + + +} \ No newline at end of file diff --git a/engine/NBGraphics/src/VertexArray.cpp b/engine/NBGraphics/src/VertexArray.cpp index b84eebf..f7ae2d3 100644 --- a/engine/NBGraphics/src/VertexArray.cpp +++ b/engine/NBGraphics/src/VertexArray.cpp @@ -60,7 +60,7 @@ VertexAttributePointer VAO::attr(GLuint idx) const { return attr_ptr; } } - THROW(BufferError(Codes::INVALID_ATTRIBUTE)); + THROW(VAOError(Codes::INVALID_ATTRIBUTE)); } void VAO::enable() const { @@ -105,121 +105,127 @@ VertexGroup::VertexGroup(VertexGroup&& other) { VertexGroup& VertexGroup::operator=(VertexGroup&& rhs) { _vertex_data = rhs._vertex_data; - _elmt_buf = std::move(rhs._elmt_buf); - _vao = std::move(rhs._vao); + _ebo = rhs._ebo; + _vao = rhs._vao; rhs._vertex_data = {}; - rhs._elmt_buf = ElementBuffer(); - rhs._vao = VAO(); + rhs._ebo = nullptr; + rhs._vao = nullptr; return *this; } -size_t VertexGroup::buffer(VertexBuffer&& buf_) { - _vertex_data.emplace_back( - std::make_shared>(std::move(buf_)) - ); - VertexBuffer* buf_ptr = _vertex_data.back().get(); - VertexAttributePointerList attrs = _vao.attributes(); +VertexGroup::VertexGroup(const VertexDataVec& vertex_data_) +: _vao(std::make_shared()), _ebo(std::make_shared()) { + setBuffers(vertex_data_); +} + +VertexGroup::VertexGroup(const VertexData& vertex_data_) +: VertexGroup(VertexDataVec({vertex_data_})) {} + +VertexGroup::VertexGroup( + const ByteVector& data_, + const VertexAttributeList& attrs_ +) : VertexGroup({std::make_shared(data_), attrs_}) {} + +size_t VertexGroup::addBuffer(const VertexData& vertex_data_) { + VertexData data = vertex_data_; + _vertex_data.emplace_back(data); + VertexAttributePointerList attrs = _vao->attributes(); GLuint idx = attrs.size(); - for (auto attr : buf_ptr->attributes) { + for (auto attr : data.attrs) { attrs.emplace_back( - VertexAttributePointer{attr, buf_ptr->id(),idx} + VertexAttributePointer{attr, data.vbo->id(),idx} ); idx++; } - _vao.attributes(attrs); + _vao->attributes(attrs); return _vertex_data.size(); } -VertexBuffer& VertexGroup::buffer(size_t idx) { - return *_vertex_data[idx]; +VertexData VertexGroup::getBuffers(size_t idx) { + return _vertex_data[idx]; } -std::vector>> VertexGroup::buffers() { + VertexDataVec VertexGroup::getBuffers() { return _vertex_data; } -size_t VertexGroup::buffers(std::vector>&& bufs_) { - _vertex_data.clear(); - for (auto& buf : bufs_) { - _vertex_data.emplace_back( - std::make_shared>(std::move(buf)) - ); - } +size_t VertexGroup::setBuffers(const VertexDataVec& vertex_data_) { + _vertex_data = vertex_data_; VertexAttributePointerList attr_ptrs; GLuint idx = 0; - for (auto buf : _vertex_data) { - for (auto attr : buf->attributes) { + for (auto data : _vertex_data) { + for (auto attr : data.attrs) { attr_ptrs.emplace_back( - VertexAttributePointer{attr, buf->id(), idx} + VertexAttributePointer{attr, data.vbo->id(), idx} ); idx++; } } - _vao.attributes(attr_ptrs); + _vao->attributes(attr_ptrs); return _vertex_data.size(); } -VertexBuffer&& VertexGroup::dropBuffer(size_t idx) { +VertexData VertexGroup::dropBuffer(size_t idx) { if (idx >= _vertex_data.size()) { THROW(BufferError(BufferError::Codes::INVALID_BUFFER)); } - std::vector> tmp; - std::shared_ptr> ret_ptr; + VertexDataVec tmp; + VertexData ret; size_t i = 0; for (auto buf : _vertex_data) { if (i == idx) { - ret_ptr = std::make_shared>(std::move(tmp[idx])); + ret = tmp[idx]; } else { - tmp.emplace_back(std::move(*buf)); + tmp.emplace_back(buf); } i++; } - buffers(std::move(tmp)); - return std::move(*ret_ptr); + setBuffers(tmp); + return ret; } VertexAttributePointer VertexGroup::attribute(size_t idx_) const { - return _vao.attr(idx_); + return _vao->attr(idx_); } void VertexGroup::enableAttr(GLuint idx) { bind(); - _vao.enable(idx); + _vao->enable(idx); unbind(); } void VertexGroup::disableAttr(GLuint idx) { bind(); - _vao.disable(idx); + _vao->disable(idx); unbind(); } void VertexGroup::disableBuffer(size_t idx) { - auto buf_idx = _vertex_data[idx]->id(); + auto buf_idx = _vertex_data[idx].vbo->id(); bind(); - for (auto attr : _vao.attributes()) { + for (auto attr : _vao->attributes()) { if (attr.buffer == buf_idx) { - _vao.disable(attr.index); + _vao->disable(attr.index); } } unbind(); } void VertexGroup::enableBuffer(size_t idx) { - auto buf_idx = _vertex_data[idx]->id(); + auto buf_idx = _vertex_data[idx].vbo->id(); bind(); - for (auto attr : _vao.attributes()) { + for (auto attr : _vao->attributes()) { if (attr.buffer == buf_idx) { - _vao.enable(attr.index); + _vao->enable(attr.index); } } unbind(); } -void VertexGroup::enable() { _vao.enable(); } +void VertexGroup::enable() { _vao->enable(); } -void VertexGroup::disable() { _vao.disable(); } +void VertexGroup::disable() { _vao->disable(); } } // namespace nb diff --git a/engine/NBGraphics/src/Window.cpp b/engine/NBGraphics/src/Window.cpp index 5229af1..7cffeca 100644 --- a/engine/NBGraphics/src/Window.cpp +++ b/engine/NBGraphics/src/Window.cpp @@ -34,8 +34,6 @@ const ErrorCodeMap WindowError::ErrorMessages = { {WindowErrorCodes::INIT_FAILED, "Could not intialized window"} }; -GLError::GLError(const std::string& msg) : std::runtime_error(msg) {} - int Window::getGLFWHint(int hint_key) { if (GLFWHints.find(hint_key) == GLFWHints.end()) { return 0; diff --git a/engine/NBGraphics/src/shader.cpp b/engine/NBGraphics/src/shader.cpp deleted file mode 100644 index f24d86e..0000000 --- a/engine/NBGraphics/src/shader.cpp +++ /dev/null @@ -1,742 +0,0 @@ -#include "Shader.h" - -// #define _PREPROC_FUNC_PARAM_NAMES_ (const ShaderPreprocessor& proc, ShaderUnit& shad, unsigned int linenum, const std::string& line, std::vector& params) - -namespace NB{ - -File::FilePath get_file_path(std::string name) { - const std::vector allowed_special_chars = { - '.', '!', '#', '$', '%', '&', '\'', '(', ')', '+', ',', '-', ';', '=', '@', '[', ']', '^', '_', '`', '~' - }; - std::vector path = {""}; - for (const char c : name) { - if (c == '/' || c == '\\') { - path.push_back(""); - } else if (std::isalnum(c)) { - path.back() += c; - } else { - bool spec_char_found = false; - for (const char sc : allowed_special_chars) { - if (c == sc) { - path.back() += c; - spec_char_found = true; - break; - } - } - if (!spec_char_found) { - throw std::runtime_error("'" + name + "' is not valid filepath."); - } - } - } - File::FilePath ret; - for (const auto& tk : path) { - if (tk == path.back()) { - size_t period = tk.find("."); - if (period == std::string::npos) { - ret.basename = tk; - ret.ext = ""; - } else { - ret.basename = tk.substr(0, period); - ret.ext = tk.substr(period); - } - } else { - ret.dir += tk + "/"; - } - } - return ret; -} - -// ShaderPreprocessorError class -ShaderPreprocessorError::ShaderPreprocessorError( - const std::string& msg, - const std::string& file, - int line -) : code(Codes::UNDEFINED), std::runtime_error(formatDebugString(msg, file, line)) {} - -ShaderPreprocessorError::ShaderPreprocessorError( - Codes err_code, - const std::string& arg, - const std::string& file, - int line -) : code(err_code), std::runtime_error(formatDebugString(errorCodeParser(err_code, arg), file, line)) {} - -std::string ShaderPreprocessorError::errorCodeParser(Codes err_code, const std::string& arg) { - switch(err_code) { - case Codes::FILE_NOT_FOUND: - return "File '" + arg + "' not found."; - case Codes::BUILTIN_NOT_FOUND: - return "Built-in '" + arg + "' not found."; - case Codes::CUSTOM: - case Codes::UNDEFINED: - return arg; - case Codes::NONE: - default: - return ""; - } -} - -// ShaderError class -ShaderError::ShaderError( - const std::string& msg, - const char* shad, - const std::string& file, - int line -) : std::runtime_error(formatString(msg, shad, file, line)) {} - -std::string ShaderError::formatString( - const std::string& msg, - const char* shad, - const std::string& file, - int line -) { - std::stringstream ret; - if (file != "") { - ret << "In file " << file; - if (line >= 0) { - ret << " at line " << line; - } - ret << ":\n\t"; - } - ret << msg; - if (shad != nullptr) { - ret << " with shader error: " << shad; - } - return ret.str(); -} - -// ShaderPreprocessor class -std::string ShaderPreprocessor::TokenName(const ShaderPreprocessor::TokenType& x) { - switch(x) { - case TK: - return "Token"; - break; - case DR: - return "Directive"; - break; - case WS: - return "Whitespace"; - break; - case NL: - return "NewLine"; - break; - case LC: - return "LineComment"; - break; - case BC: - return "BlockComment"; - break; - default: - return "Unrecognized"; - break; - } -} - -ShaderPreprocessor::ShaderPreprocessor() {} - -File ShaderPreprocessor::loadFromBase(const std::string path, const std::string base) const { - File ret; - std::ifstream filestream; - filestream.open(base + path); - if (filestream.is_open()) { - ret.path = get_file_path(base + path); - ret.src << filestream.rdbuf(); - return ret; - } - filestream.close(); - std::string ext; - for (const auto& kv : AcceptedExtensions) { - ext = kv.first; - filestream.open(base + path + ext); - if (filestream.is_open()) { - ret.path = get_file_path(base + path + ext); - ret.src << filestream.rdbuf(); - return ret; - } - filestream.close(); - } - throw ShaderPreprocessorError(Codes::FILE_NOT_FOUND, base + path); -} - -File ShaderPreprocessor::loadFromDirectories(const std::string name) const { - File ret; - std::ifstream fstream; - for (const std::string& path : Directories) { - fstream.open(path + name); - if (fstream.is_open()) { - ret.path = get_file_path(path + name); - ret.src << fstream.rdbuf(); - return ret; - } - fstream.close(); - } - throw ShaderPreprocessorError(Codes::FILE_NOT_FOUND, name); -} - -File ShaderPreprocessor::load(const std::string path, bool builtin_first) const { - if(builtin_first) { - return load_BuiltInFirst(path); - } - return load_FilesFirst(path); -} - -File ShaderPreprocessor::loadFromBuiltIn(const std::string name) const { - File ret; - //std::stringstream ret; - decltype(BuiltIns)::const_iterator builtin_it = BuiltIns.find(name); - if (builtin_it != BuiltIns.end()) { - ret.path = File::FilePath{"builtin:", name, ""}; - ret.src << builtin_it->second; - return ret; - } - throw ShaderPreprocessorError(Codes::BUILTIN_NOT_FOUND, name); -} - -File ShaderPreprocessor::load_FilesFirst(const std::string path) const { - try { - return loadFromBase(path); - } catch (ShaderPreprocessorError e) { - if (e.code == Codes::FILE_NOT_FOUND) { - try { - return loadFromDirectories(path); - } catch (ShaderPreprocessorError f) { - if (f.code == Codes::FILE_NOT_FOUND) { - try { - return loadFromBuiltIn(path); - } catch(ShaderPreprocessorError g) { - if (g.code == Codes::BUILTIN_NOT_FOUND) { - throw ShaderPreprocessorError(Codes::FILE_NOT_FOUND, path); - } else { throw g; } - } - } else { throw f; } - } - } else { throw e; } - } -} - -File ShaderPreprocessor::load_BuiltInFirst(const std::string path) const { - try { - return loadFromBuiltIn(path); - } catch (ShaderPreprocessorError f) { - if (f.code == Codes::BUILTIN_NOT_FOUND) { - try { - return loadFromDirectories(path); - } catch (ShaderPreprocessorError e) { - if (e.code == Codes::FILE_NOT_FOUND) { - return loadFromBase(path); - } else { - throw e; - } - } - } else { - throw f; - } - } - -} - -std::vector ShaderPreprocessor::tokenize(const std::string& code) const { - enum State { - FSlash, - WhiteSpace, - LineComment, - BlockComment, - BlockCommentEndStar, - Directive, - Token - }; - - std::vector tks; - - std::string token = ""; - State state = WhiteSpace; - for(char c : code) { - if (c==13) { - continue; - } - switch(state) { - case WhiteSpace: - if (c=='/') { - if (token != "") { tks.push_back({WS, token}); } - token = c; - state = FSlash; - } else if (c=='#') { - if (token != "") { tks.push_back({WS, token}); } - token = c; - state = Directive; - } else if (c=='\n') { - if (token != "") { tks.push_back({WS, token}); } - tks.push_back({NL, "\n"}); - token = ""; - state = WhiteSpace; - } else if (std::isblank(c)) { - token += c; - } else { - if (token != "") { tks.push_back({WS, token}); } - token = c; - state = Token; - } - break; - case FSlash: - if (c=='/') { - token += c; - state = LineComment; - } else if (c=='*') { - token += c; - state = BlockComment; - } else if (c=='\n') { - tks.push_back({TK, token}); - tks.push_back({NL, "\n"}); - token = ""; - state = WhiteSpace; - } else if (std::isblank(c)) { - tks.push_back({TK, token}); - token = c; - }else { - token += c; - state = Token; - } - break; - case LineComment: - if (c=='\n') { - tks.push_back({LC, token}); - tks.push_back({NL, "\n"}); - token = ""; - state = WhiteSpace; - } else { - token += c; - } - break; - case BlockComment: - token += c; - if (c=='*') { - state = BlockCommentEndStar; - } - break; - case BlockCommentEndStar: - token += c; - if (c=='/') { - tks.push_back({BC, token}); - token = ""; - state = WhiteSpace; - } else { - state = BlockComment; - } - break; - case Directive: - if (c=='\n') { - tks.push_back({DR, token}); - tks.push_back({NL, "\n"}); - token = ""; - state = WhiteSpace; - } else if (c=='/') { - tks.push_back({DR, token}); - token = c; - state = FSlash; - } else { - token += c; - } - break; - case Token: - if (c=='\n') { - tks.push_back({TK, token}); - tks.push_back({NL, "\n"}); - token = ""; - state = WhiteSpace; - } else if (std::isblank(c)) { - tks.push_back({TK, token}); - token = c; - state = WhiteSpace; - } else if (c=='/') { - tks.push_back({TK, token}); - token = c; - state = FSlash; - }else { - token += c; - } - break; - default: - break; - } - - } - - switch(state) { - case WhiteSpace: - if (token != "") { tks.push_back({WS, token}); } - case FSlash: - tks.push_back({TK, token}); - break; - case LineComment: - tks.push_back({LC, token}); - break; - case BlockComment: - case BlockCommentEndStar: - tks.push_back({BC, token}); - break; - case Directive: - tks.push_back({DR, token}); - break; - case Token: - tks.push_back({TK, token}); - break; - default: - break; - } - - return tks; -} - -ShaderUnit& ShaderPreprocessor::preprocess(const std::string& code, ShaderUnit& shad) const { - typedef ShaderPreprocessor::Token Token; - std::vector tks = tokenize(code); - - for (int i{0}; i < tks.size(); ++i) { - switch(tks[i].first) { - case DR: - directive_dispatch(shad, tks[i].second); - break; - case TK: - case NL: - case LC: - case BC: - case WS: - default: - shad.preprocSource += tks[i].second; - break; - } - } - - if (shad.vMajor == 0 && shad.vMinor == 0) { - shad.vMajor = 1; - shad.vMinor = 10; - } - return shad; -} - -ShaderUnit ShaderPreprocessor::preprocess(File file, GLenum shader_type) const { - ShaderUnit ret; - ret.file = file; - if (shader_type) { - ret.type = shader_type; - } else { - decltype(AcceptedExtensions.begin()) find_type = AcceptedExtensions.find(file.path.ext); - if (find_type != AcceptedExtensions.end()) { - ret.type = find_type->second; - } - } - preprocess(file.src.str(), ret); - return ret; -} - -ShaderUnit ShaderPreprocessor::preprocess(const std::string& code, GLenum shader_type) const { - File local; - local.path = File::FilePath{"live:", "live", ".shad"}; - return preprocess(local, shader_type); -} - -ShaderProgram ShaderPreprocessor::CreateShaderProgram(std::vector shads) const { - std::vector _shader_units; - for (const auto& name : shads) { - _shader_units.push_back(preprocess(load(name))); - } - return ShaderProgram::CreateShaderProgram(_shader_units); -} - -ShaderProgram ShaderPreprocessor::ReloadFromFile(const ShaderProgram& rhs) const { - std::vector shader_names; - shader_names.reserve(rhs._shader_units.size()); - std::string filename; - for (const ShaderUnit& shad : rhs._shader_units) { - filename = shad.file.path.dir + shad.file.path.basename + shad.file.path.ext; - shader_names.emplace_back(filename); - } - return CreateShaderProgram(shader_names); -} - -bool ShaderPreprocessor::directive_dispatch(ShaderUnit& shad, const std::string& line) const { - StringVec dir_tks = {""}; - for (char c : line) { - if (std::isblank(c)) { - if (dir_tks.back() != "") { - dir_tks.push_back(""); - } - } else { - dir_tks.back() += c; - } - } - if (!dir_tks.size()) { return false; } - - if (dir_tks[0][0] != '#') { return false; } - - if (dir_tks[0] == "#define") { - return preprocessor_define(shad, dir_tks, line); - } else if (dir_tks[0] == "#version") { - return preprocessor_version(shad, dir_tks, line); - } else if (dir_tks[0] == "#include") { - return preprocessor_include(shad, dir_tks, line); - } - return false; -} - -typedef std::vector StringVec; - -bool ShaderPreprocessor::preprocessor_include( - ShaderUnit& shad, - const StringVec& tokens, - const std::string& line -) const -{ - try { - if (tokens[0] != "#include") { return false; } - } catch (std::out_of_range e) { - return false; - } - std::string path = ""; - for (const auto& tk : tokens) { - if (tk != tokens.front()) { - path += tk; - } - } - // Add file-inclusion base + - // Do path cleanup + - // Restructure preprocessing data flow - std::string filename = path.substr(1, path.size()-2); - try { - if (path[0] == '"' && path.back() == '"') { - preprocess(load(filename).src.str(), shad); - return true; - } else if (path[0] == '<' && path.back() == '>') { - preprocess(load(filename, true).src.str(), shad); - return true; - } - } catch (ShaderPreprocessorError e) { - if (e.code == Codes::FILE_NOT_FOUND) { - std::cout << "COULD NOT FIND " << filename << ".\n"; - } else { - throw e; - } - } - return false; -} - -bool ShaderPreprocessor::preprocessor_define(ShaderUnit& shad, const StringVec& tokens, const std::string& line) const { - shad.preprocSource += line; - try { - if (tokens[0] != "#define") { return false; } - try { - shad.defines[tokens[1]] = tokens[2]; - } catch (std::length_error& f) { - shad.defines[tokens[1]] = ""; - } - return true; - } catch (std::out_of_range& e) { - return false; - } -} - -bool ShaderPreprocessor::preprocessor_version(ShaderUnit& shad, const StringVec& tokens, const std::string& line) const { - shad.preprocSource += line; - std::cout << "Shader version: "; - try { - if (tokens[0] != "#version") { return false; } - if (tokens[1].size() == 3) { - short vMajor = tokens[1][0]-'0'; - short vMinorA = tokens[1][1]-'0'; - short vMinorB = tokens[1][2]-'0'; - if (vMajor > 10 || vMinorA > 10 || vMinorB > 10) { - return false; - } - shad.vMajor = vMajor; - shad.vMinor = vMinorA*10 + vMinorB; - shad.profile = AcceptedProfiles.at(tokens[2]); - std::cout << shad.vMajor << "." << shad.vMinor << "\n"; - return true; - } else { - return false; - } - } catch (std::out_of_range& e) { - return false; - } -} - - -/* bool ShaderPreprocessor::preprocessor_uniform( - ShaderUnit& shad, - const std::string& type, - const std::string& name -) const { - std::string type_str = ""; - unsigned int type_str_len = 0; - for (const char& c : type) { - if (type_str_len) { - if (std::isdigit(c)) { - type_str += c; - continue; - } else if (c=='[') { - type_str += '_'; - }else if (c == ']' || std::isblank(c)){ - continue; - } else { - return false; - } - } else { - if (std::isalnum(c)) { - type_str += c; - continue; - } else if (c == '[') { - type_str_len = type_str.length(); - type_str += '_'; - continue; - } else { - return false; - } - } - } - std::string name_str = ""; - unsigned int name_str_len = 0; - for (const char& c : name) { - if (c == ';') { - break; - } - if (name_str_len) { - if (std::isdigit(c)) { - type_str.insert(type_str_len, 1, c); - type_str_len++; - continue; - } else if (c=='[') { - type_str.insert(type_str_len, "_"); - type_str_len++; - continue; - }else if (c == ']' || std::isblank(c)){ - continue; - } else { - return false; - } - } else { - if (std::isalnum(c)) { - name_str += c; - continue; - } else if ( c == '[') { - name_str_len = name_str.length(); - type_str.insert(type_str_len, "_"); - type_str_len++; - continue; - } else { - return false; - } - } - } - shad.uniforms.push_back(UniformHandle{ - name_str, - type_str, - 0x0, - 0x0 - }); - return true; -} */ - - -// ShaderProgram - -ShaderProgram::ShaderProgram(ShaderProgram&& rhs) { - _shader_units = rhs._shader_units; - _id = rhs._id; - rhs._id = 0; -} - -ShaderProgram::~ShaderProgram() { - glDeleteProgram(_id); -} - -ShaderProgram& ShaderProgram::operator=(ShaderProgram&& rhs) { - _shader_units = rhs._shader_units; - _id = rhs._id; - rhs._id = 0; - return *this; -} - - -ShaderProgram ShaderProgram::CreateShaderProgram(std::vector& shaders) { - int success; - ShaderProgram ret(shaders); - char infoLog[512]; - unsigned int shad_id; - std::vector shad_ids; - shad_ids.reserve(shaders.size()); - for (auto& shad : ret._shader_units) { - const char* source = shad.preprocSource.data(); - shad_id = glCreateShader(shad.type); - shad_ids.emplace_back(shad_id); - glShaderSource(shad_id, 1, &source, NULL); - glCompileShader(shad_id); - glGetShaderiv(shad_id, GL_COMPILE_STATUS, &success); - if (!success) { - glGetShaderInfoLog(shad_id, 512, NULL, infoLog); - File::FilePath& fp = shad.file.path; - std::string filename = fp.dir + fp.basename + fp.ext; - // std::cout << "Could not compile '" + filename + "': " << infoLog << "\n"; - // return *ret; - throw ShaderError("Could not compile '" + filename + "'.", infoLog); - } - } - - ret._id = glCreateProgram(); - for(auto& id : shad_ids) { - glAttachShader(ret._id, id); - } - glLinkProgram(ret._id); - glGetProgramiv(ret._id, GL_LINK_STATUS, &success); - if (!success) { - glGetProgramInfoLog(ret._id, 512, NULL, infoLog); - throw ShaderError("Could not link shader program.", infoLog); - } - for (auto& id : shad_ids) { - glDeleteShader(id); - } - return ret; -} - -unsigned int ShaderProgram::id() const { return _id; } - -void ShaderProgram::use() const { - glUseProgram(_id); -} - -std::vector ShaderProgram::getShaders() const { - return _shader_units; -} - -ShaderUnit ShaderProgram::getShaders(unsigned int idx) const { - return _shader_units[idx]; -} - -void ShaderProgram::setBool(const std::string& name, bool value) const { - glUniform1i(glGetUniformLocation(_id, name.c_str()), (int)value); -} - -void ShaderProgram::setInt(const std::string& name, int value) const { - glUniform1i(glGetUniformLocation(_id, name.c_str()), (int)value); -} - -void ShaderProgram::setFloat(const std::string& name, float value) const { - glUniform1f(glGetUniformLocation(_id, name.c_str()), (int)value); -} - -void ShaderProgram::setMat4(const std::string& name, glm::mat4& value) const { - glUniformMatrix4fv(glGetUniformLocation(_id, name.c_str()), 1, GL_FALSE, glm::value_ptr(value)); -} - -/* // Shader class -Shader::Shader() { _id = 0x0; } - -Shader::Shader(const Shader& cpy_shader) { _id = cpy_shader._id; } - -Shader& Shader::operator=(const Shader& cpy_shader) { _id = cpy_shader._id; return *this; } - -void Shader::use() const{ - glUseProgram(_id); -} - -*/ - -} \ No newline at end of file diff --git a/engine/NBGraphics/tests/CMakeLists.txt b/engine/NBGraphics/tests/CMakeLists.txt index 62ecefc..8e6d9d6 100644 --- a/engine/NBGraphics/tests/CMakeLists.txt +++ b/engine/NBGraphics/tests/CMakeLists.txt @@ -9,8 +9,6 @@ if (NB_BUILD_TESTS) target_link_libraries(TestWindow NBCore NBGraphics -# GTest::gtest_main ) -# gtest_discover_tests(TestWindow) endif() \ No newline at end of file diff --git a/engine/NBGraphics/tests/TestWindow.cpp b/engine/NBGraphics/tests/TestWindow.cpp index 03a7c0e..765c9e6 100644 --- a/engine/NBGraphics/tests/TestWindow.cpp +++ b/engine/NBGraphics/tests/TestWindow.cpp @@ -1,9 +1,8 @@ #include "GLLoad.hpp" -// #define _NB_AUTOLOG +#include "ProgramPipeline.hpp" #include "VertexArray.hpp" #include "Window.hpp" - int main() { nb::logger.log("Howdy!"); nb::Window window(200, 200, "Hello!"); @@ -11,8 +10,53 @@ int main() { window.setWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); window.init(); + nb::logger.log("Goob"); + + auto vert = std::make_shared( + GL_VERTEX_SHADER, + "#version 330 core\n" + "layout (location = 0) in vec2 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);\n" + "}\0" + ); + + LOG("Vertex Shader: " + vert->log()); + + auto frag = std::make_shared( + GL_FRAGMENT_SHADER, + "#version 330 core\n" + "out vec4 FragColor;\n" + "void main()\n" + "{\n" + " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0" + ); + + LOG("Fragment shader: " + frag->log()); + + nb::ByteVector data = nb::vectorToBytes({ + -0.5, -0.5, 0.5, -0.5, 0.0, 0.5 + }); + + nb::Program prog({vert, frag}); + prog.bind(); + + nb::VertexGroup tri(data, { + nb::VertexAttribute{ + 2, + GL_FLOAT, + false, + {0, 8} + } + }); + tri.bind(); + GLFWwindow* window_ptr = window.getWindow(); - while(!glfwWindowShouldClose(window_ptr)) {} + while(!glfwWindowShouldClose(window_ptr)) { + glDrawArrays(GL_TRIANGLES, 0, 3); + } return 0; } \ No newline at end of file -- 2.43.0 From 2c4392a51e5325896b67d1339ca3bd03185ec09b Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:49:27 -0500 Subject: [PATCH 17/18] Change invalid buffer binding to warning instead of error --- engine/NBGraphics/Buffers.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/NBGraphics/Buffers.hpp b/engine/NBGraphics/Buffers.hpp index 0e08b99..8990d8f 100644 --- a/engine/NBGraphics/Buffers.hpp +++ b/engine/NBGraphics/Buffers.hpp @@ -72,10 +72,10 @@ class Buffer : public OpenGLObject { if (_id) { glBindBuffer(Target, _id); } else { - THROW(BufferError( + WARN(BufferError( Codes::INVALID_BUFFER, "w/ BufferType " + BufferTypes.at(Target) - )); + ), 0xFE); } } virtual void unbind() const override { glBindBuffer(Target, 0); } -- 2.43.0 From 75bda91302ba312ca3c903545b6be61e1d0c41c0 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:50:10 -0500 Subject: [PATCH 18/18] Forgot to actually compile the shader :P --- engine/NBGraphics/src/ProgramPipeline.cpp | 8 +++++++- engine/NBGraphics/tests/TestWindow.cpp | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/engine/NBGraphics/src/ProgramPipeline.cpp b/engine/NBGraphics/src/ProgramPipeline.cpp index d4cea76..e45b65a 100644 --- a/engine/NBGraphics/src/ProgramPipeline.cpp +++ b/engine/NBGraphics/src/ProgramPipeline.cpp @@ -17,7 +17,13 @@ const ErrorCodeMap ProgramError::ErrorMessages = { Shader::Shader(GLenum target_, const std::string& source_) : target(target_) { declare(); + const char* src_ptr= source_.data(); + glShaderSource(_id, 1, &src_ptr, NULL); + glCompileShader(_id); _success = status(GL_COMPILE_STATUS); + if (!_success) { + WARN(log(), 0x0FE); + } } Shader::Shader(Shader&& cpy) : target(cpy.target) { @@ -49,7 +55,7 @@ Program::Program(SharedVector shaders_) { glLinkProgram(_id); _success = status(GL_LINK_STATUS); if (!_success) { - WARN(log(), 0x01); + WARN(log(), 0x0FE); } } diff --git a/engine/NBGraphics/tests/TestWindow.cpp b/engine/NBGraphics/tests/TestWindow.cpp index 765c9e6..daacb70 100644 --- a/engine/NBGraphics/tests/TestWindow.cpp +++ b/engine/NBGraphics/tests/TestWindow.cpp @@ -5,7 +5,7 @@ int main() { nb::logger.log("Howdy!"); - nb::Window window(200, 200, "Hello!"); + nb::Window window(400, 400, "Hello!"); window.setWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); window.setWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); window.init(); @@ -56,6 +56,10 @@ int main() { GLFWwindow* window_ptr = window.getWindow(); while(!glfwWindowShouldClose(window_ptr)) { glDrawArrays(GL_TRIANGLES, 0, 3); + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glfwPollEvents(); + glfwSwapBuffers(window_ptr); } return 0; -- 2.43.0