diff --git a/engine/NBGraphics/CMakeLists.txt b/engine/NBGraphics/CMakeLists.txt index 49d3e76..f7b6b76 100644 --- a/engine/NBGraphics/CMakeLists.txt +++ b/engine/NBGraphics/CMakeLists.txt @@ -1,10 +1,11 @@ cmake_minimum_required(VERSION 3.10) project(NBGraphics VERSION 0.1) +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + set(GLAD_PATH ${NBENGINE_ROOT}/../glad/) -set(STBIMAGE_PATH ${NBENGINE_ROOT}/../stbi_image) get_filename_component(GLAD_PATH ${GLAD_PATH} ABSOLUTE) -get_filename_component(STBIMAGE_PATH ${STBIMAGE_PATH} ABSOLUTE) set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}" @@ -21,6 +22,10 @@ else() endif() set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +if (NB_MONITOR_OPENGL_CALLS) + add_compile_definitions(_NB_MONITOR_OPENGL_CALLS) +endif() + toAbsolutePath(NB_GRAPHICS_SOURCE ./src/Buffers.cpp ./src/FrameBuffers.cpp @@ -53,29 +58,45 @@ add_library(NBGraphics ${GLAD_PATH}/src/glad.c ) add_library(NBEngine::Graphics ALIAS NBGraphics) +add_dependencies(NBGraphics NBCore) +add_dependencies(NBGraphics glfw) target_link_libraries(NBGraphics PUBLIC glfw PUBLIC NBCore ) -get_target_property(GLFW_INTERFACE_INCLUDES glfw INTERFACE_INCLUDE_DIRECTORIES) -#include_directories(${GLFW_INTERFACE_INCLUDES}) target_include_directories(NBGraphics - PUBLIC "$" + PUBLIC "$" PUBLIC "$" - PUBLIC "${STBIMAGE_PATH}" PUBLIC "${GLAD_PATH}/include" ) +export( + TARGETS NBGraphics + FILE "${CMAKE_BINARY_DIR}/cmake/NBGraphicsTargets.cmake" + NAMESPACE NBEngine:: +) +configure_package_config_file( + "NBGraphicsConfig.cmake.in" + "${CMAKE_BINARY_DIR}/cmake/NBGraphicsConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake + PATH_VARS CMAKE_INSTALL_LIBDIR +) +write_basic_package_version_file( + "${CMAKE_BINARY_DIR}/cmake/NBGraphicsConfigVersion.cmake" + COMPATIBILITY AnyNewerVersion +) + if (NBENGINE_INSTALL) message("Installing NBGraphics to ${CMAKE_INSTALL_PREFIX}") - include(GNUInstallDirs) - include(CMakePackageConfigHelpers) install( - TARGETS NBGraphics + TARGETS NBGraphics EXPORT NBGraphicsTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + INCLUDES DESTINATION include ) install( - DIRECTORY "${PROJECT_SOURCE_DIR}/include/NBGraphics" + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/NBGraphics" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" ) @@ -84,20 +105,10 @@ if (NBENGINE_INSTALL) DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake NAMESPACE NBEngine:: ) - configure_package_config_file( - "NBGraphicsConfig.cmake.in" - "NBGraphicsConfig.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake - PATH_VARS CMAKE_INSTALL_LIBDIR - ) - write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/NBGraphicsConfigVersion.cmake" - COMPATIBILITY AnyNewerVersion - ) install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/NBGraphicsConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/NBGraphicsConfigVersion.cmake" - DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" + "${CMAKE_BINARY_DIR}/cmake/NBGraphicsConfig.cmake" + "${CMAKE_BINARY_DIR}/cmake/NBGraphicsConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_PREFIX}/CMake" ) endif() diff --git a/engine/NBGraphics/NBGraphicsConfig.cmake.in b/engine/NBGraphics/NBGraphicsConfig.cmake.in index bef4f69..4cf119a 100644 --- a/engine/NBGraphics/NBGraphicsConfig.cmake.in +++ b/engine/NBGraphics/NBGraphicsConfig.cmake.in @@ -1,2 +1,6 @@ @PACKAGE_INIT@ -include("${CMAKE_CURRENT_LIST_DIR}/NBGraphicsTargets.cmake") \ No newline at end of file +include("${CMAKE_CURRENT_LIST_DIR}/NBGraphicsTargets.cmake") +include(CMakeFindDependencyMacro) +find_dependency(NBCore REQUIRED) +find_dependency(OpenGL REQUIRED) +find_dependency(glfw3 REQUIRED) \ No newline at end of file diff --git a/engine/NBGraphics/include/NBGraphics/Buffers.hpp b/engine/NBGraphics/include/NBGraphics/Buffers.hpp index 09d0244..7096a0b 100644 --- a/engine/NBGraphics/include/NBGraphics/Buffers.hpp +++ b/engine/NBGraphics/include/NBGraphics/Buffers.hpp @@ -14,7 +14,7 @@ namespace nb { -extern const std::unordered_map BufferTypes; +extern const ConstantMap BufferTypes; template struct GLSLEnum; @@ -72,7 +72,7 @@ class Buffer : public OpenGLObject { Buffer(GLenum target) : Target(target) {} virtual GLuint declare() override { if (!_id) { - glGenBuffers(1, &_id); + OPENGL_CALL(glGenBuffers(1, &_id)); } bind(); return _id; @@ -80,7 +80,7 @@ class Buffer : public OpenGLObject { virtual void remove() override { if (_id) { unbind(); - glDeleteBuffers(1, &_id); + OPENGL_CALL(glDeleteBuffers(1, &_id)); _id = 0; } } @@ -93,15 +93,17 @@ class Buffer : public OpenGLObject { virtual void bind() const override { if (_id) { - glBindBuffer(Target, _id); + OPENGL_CALL(glBindBuffer(Target, _id)); } else { - THROW(OGLError( - OGLError::Codes::INVALID_OBJECT, - "w/ BufferType " + BufferTypes.at(Target) + THROW(OpenGLObjectError( + OpenGLObjectError::Codes::INVALID_OBJECT, + "w/ BufferType " + BufferTypes[Target] )); } } - virtual void unbind() const override { glBindBuffer(Target, 0); } + virtual void unbind() const override { + OPENGL_CALL(glBindBuffer(Target, 0)); + } GLenum usage() const; size_t size() const; ByteVector data() const; diff --git a/engine/NBGraphics/include/NBGraphics/Draw.hpp b/engine/NBGraphics/include/NBGraphics/Draw.hpp index d94d1af..1b5602b 100644 --- a/engine/NBGraphics/include/NBGraphics/Draw.hpp +++ b/engine/NBGraphics/include/NBGraphics/Draw.hpp @@ -9,13 +9,12 @@ #include #include -#include -#include -#include +#include +#include #define THROW_DRAW_ERROR(msg) throw DrawError(msg, __FILE__, __LINE__); -namespace NB{ +namespace nb{ class DrawError : public std::runtime_error { public: diff --git a/engine/NBGraphics/include/NBGraphics/FrameBuffers.hpp b/engine/NBGraphics/include/NBGraphics/FrameBuffers.hpp index 54c57df..c3a2df2 100644 --- a/engine/NBGraphics/include/NBGraphics/FrameBuffers.hpp +++ b/engine/NBGraphics/include/NBGraphics/FrameBuffers.hpp @@ -29,19 +29,25 @@ class RenderBuffer : public RenderTarget { protected: GLuint declare() override { if (!_id) { - glRenderbufferStorage( + OPENGL_CALL( + glGenRenderbuffers(1, &_id) + ); + bind(); + OPENGL_CALL(glRenderbufferStorage( GL_RENDERBUFFER, format, width, height - ); + )); + return _id; } + bind(); return _id; } void remove() override { if (_id) { unbind(); - glDeleteRenderbuffers(1, &_id); + OPENGL_CALL(glDeleteRenderbuffers(1, &_id)); _id = 0; } } @@ -50,11 +56,14 @@ class RenderBuffer : public RenderTarget { const unsigned int width; const unsigned int height; const GLenum format; - template - RenderBuffer(unsigned int width_, unsigned int height_) : + RenderBuffer( + GLenum format_, + unsigned int width_, + unsigned int height_ + ) : + format(format_), width(width_), height(height_), - format(OGLPixelFormat::glFormat), RenderTarget(GL_RENDERBUFFER) { declare(); } RenderBuffer(RenderBuffer&& rhs) : @@ -66,16 +75,16 @@ class RenderBuffer : public RenderTarget { RenderBuffer& operator=(RenderBuffer&&) = delete; void bind() const override { if (_id) { - glBindRenderbuffer(GL_RENDERBUFFER, _id); + OPENGL_CALL(glBindRenderbuffer(GL_RENDERBUFFER, _id)); } else { - THROW(OGLError( - OGLError::Codes::INVALID_OBJECT, + THROW(OpenGLObjectError( + OpenGLObjectError::Codes::INVALID_OBJECT, "w/ RenderBuffer" )); } } void unbind() const override { - glBindRenderbuffer(GL_RENDERBUFFER, 0); + OPENGL_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); } }; @@ -85,8 +94,10 @@ class FrameBufferBase : public OpenGLObject { static bool texTypeIs2D(GLenum texType) { switch(texType) { case GL_TEXTURE_2D: - default: return true; + case GL_TEXTURE_1D: + default: + return false; break; } } @@ -98,6 +109,19 @@ class FrameBufferBase : public OpenGLObject { GLuint declare() override; void remove() override; std::shared_ptr detach(GLenum); + void attach( + GLenum attachment, + std::shared_ptr renderbuffer + ); + + public: + const GLenum Target; + void bind() const override; + void unbind() const override; + GLenum status() const; + bool complete() const; + AttachmentMap getAllBuffers() const; + std::shared_ptr getBuffer(GLenum) const; void attach( GLenum attachment, std::shared_ptr texture, @@ -109,32 +133,6 @@ class FrameBufferBase : public OpenGLObject { unsigned int level, unsigned int layer ); - void attach( - GLenum attachment, - std::shared_ptr renderBuffer - ) { - declare(); - if (attachment == GL_NONE) { - THROW(FrameBufferError(FrameBufferError::INVALID_VALUE, - "Cannot attach RenderBuffer to `GL_NONE`" - )); - } - glFramebufferRenderbuffer( - Target, - attachment, - GL_RENDERBUFFER, - renderBuffer->id() - ); - _attachments[attachment] = renderBuffer; - } - - public: - const GLenum Target; - void bind() const override; - void unbind() const override; - GLenum status() const; - AttachmentMap getAllBuffers() const; - std::shared_ptr getBuffer(GLenum) const; }; class ReadFrameBuffer; @@ -178,12 +176,6 @@ class WriteFrameBuffer : public virtual FrameBufferBase { WriteFrameBuffer(); WriteFrameBuffer& operator=(ReadFrameBuffer&&); WriteFrameBuffer& operator=(WriteFrameBuffer&&); - template - void attach( - GLenum attachment, - std::shared_ptr texture, - T... args - ) { FrameBufferBase::attach(attachment, texture, args...); } DrawTexVec getWriteBuffers() const; std::vector getWriteLocations() const; DrawTexVec setWriteBuffers(const std::vector& attachments); diff --git a/engine/NBGraphics/include/NBGraphics/GLLoad.hpp b/engine/NBGraphics/include/NBGraphics/GLLoad.hpp index 8158ecd..298d009 100644 --- a/engine/NBGraphics/include/NBGraphics/GLLoad.hpp +++ b/engine/NBGraphics/include/NBGraphics/GLLoad.hpp @@ -5,4 +5,8 @@ #include #include +namespace nb { + +} // namespace nb + #endif \ No newline at end of file diff --git a/engine/NBGraphics/include/NBGraphics/Image.hpp b/engine/NBGraphics/include/NBGraphics/Image.hpp index 4301193..c754871 100644 --- a/engine/NBGraphics/include/NBGraphics/Image.hpp +++ b/engine/NBGraphics/include/NBGraphics/Image.hpp @@ -134,40 +134,95 @@ class Image; template class Image> { + private: + Error<> sizeCompare(const Image& rhs) { + const std::string errmsg = "Cannot assign images of different size"; + if (width != rhs.width) { + return Error<>( + Error<>::VALUE_ERROR, + errmsg+"[ Width: "+std::to_string(width)+\ + " != "+std::to_string(rhs.width)+" ]" + ); + } + if (height != rhs.height) { + return Error<>( + Error<>::VALUE_ERROR, + errmsg+"[ Width: "+std::to_string(width)+\ + " != "+std::to_string(rhs.width)+" ]" + ); + } + return Error<>("NoError"); + } + protected: using Codes = ImageError::Codes; + bool _data_managed; T* _data; - Image(unsigned int x, unsigned int y) - : width(x), height(y), _data(nullptr) {} + void clear() { + if (_data_managed) { + delete[] _data; + _data_managed = false; + } + _data = nullptr; + } public: using PixelType = Pixel; static constexpr size_t NumberChannels = sizeof...(Channels); const unsigned int width; const unsigned int height; - Image(unsigned int x, unsigned int y, const T* data) - : Image(x, y) { - size_t data_size = width*height*NumberChannels; - _data = new T[data_size]; - std::memcpy(_data, data, data_size*sizeof(T)); + static Image&& CreateImageStorage( + unsigned int width, + unsigned int height, + T* data=nullptr + ) { + unsigned int data_size = NumberChannels*width*height*sizeof(T); + T* data_ptr = new T[data_size]; + auto& ret = Image(width, height, data_ptr); + if (data) { + std::memcpy(data_ptr, data, data_size); + } + ret._data_managed = true; + return std::move(ret); + } + Image(unsigned int x, unsigned int y, T* data=nullptr) + : width(x), height(y), _data(data), _data_managed(false) {} + Image(const Image& cpy) + : Image(cpy.width, cpy.height) { + *this = cpy; } - Image(const Image&) = delete; - Image& operator=(const Image&) = delete; - Image& operator=(Image&&) = delete; Image(Image&& mv) - : width(mv.width), height(mv.height), _data(mv._data) { - mv._data = nullptr; + : Image(mv.width, mv.height) { + *this = std::move(mv); + } + Image& operator=(const Image& cpy) { + if (_data_managed) { + THROW(Error<>(Error<>::OVERWRITE_ERROR)); + } + const Error<> sizeErr = sizeCompare(cpy); + if (sizeErr.code!=1) { THROW(sizeErr); } + _data = cpy._data; + return this; + } + Image& operator=(Image&& mv) { + if (_data_managed) { + THROW(Error<>(Error<>::OVERWRITE_ERROR)); + } + const Error<> sizeErr = sizeCompare(mv); + if (sizeErr.code!=1) { THROW(sizeErr); } + _data = mv._data; + _data_managed = mv._data_managed; + mv._data_managed = false; + return this; } - ~Image() { - if (_data) { - delete[] _data; - } + virtual ~Image() { + clear(); } const T* data() const { return _data; } - Image&& copy() const { - return Image(width, height, _data); + Image&& copy() const { + return CreateImageStorage(width, height, _data); } PixelReference at(unsigned int x, unsigned int y) { if (!(x> { }; -template -class ImageReference; - -template -class ImageReference> : public Image> { - protected: - using Base = Image>; - using Base::_data; - - public: - using Base::width; - using Base::height; - using Base::copy; - ImageReference(unsigned int x, unsigned int y, T* data) - : Base(x, y) { - _data = data; - } - ~ImageReference() noexcept { - Base::_data = nullptr; - } - -}; - } // namespace nb #endif // _NB_IMAGE \ No newline at end of file diff --git a/engine/NBGraphics/include/NBGraphics/OGLObjects.hpp b/engine/NBGraphics/include/NBGraphics/OGLObjects.hpp index 0f7d46c..4171b78 100644 --- a/engine/NBGraphics/include/NBGraphics/OGLObjects.hpp +++ b/engine/NBGraphics/include/NBGraphics/OGLObjects.hpp @@ -2,14 +2,40 @@ #ifndef _NB_OGL_OBJECTS #define _NB_OGL_OBJECTS -#include - #include +#include +#include namespace nb { -class OGLError : public Error { - using Base = Error; +typedef ConstantMap GLEnumTableType; + +extern const GLEnumTableType GLenumTable; + +class OpenGLError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + NO_ERROR = GL_NO_ERROR, + INVALID_ENUM = GL_INVALID_ENUM, + INVALID_VALUE = GL_INVALID_VALUE, + INVALID_OPERATION = GL_INVALID_OPERATION, + INVALID_FRAMEBUFFER_OPERATION = GL_INVALID_FRAMEBUFFER_OPERATION, + OUT_OF_MEMORY = GL_OUT_OF_MEMORY, + STACK_UNDERFLOW = GL_STACK_UNDERFLOW, + STACK_OVERFLOW = GL_STACK_OVERFLOW + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; + static OpenGLError status(); +}; + +class OpenGLObjectError : public Error { + using Base = Error; public: using Base::Base; @@ -35,7 +61,7 @@ class OpenGLObject { GLuint id() const { return _id; } protected: - using Codes = OGLError::Codes; + using Codes = OpenGLObjectError::Codes; OpenGLObject() = default; virtual GLuint declare() = 0; @@ -45,4 +71,43 @@ class OpenGLObject { }; } // namespace nb +#ifndef OPENGL_CALL + #ifdef _NB_MONITOR_OPENGL_CALLS + namespace NB_OPENGL_CALL_MONITORING { + template + inline auto run_expression( + const std::string& file, + unsigned int line, + Fn fn + ) { + auto check_ = [file, line]() { + const auto no_err = nb::OpenGLError::NO_ERROR; + auto stat = nb::OpenGLError::status(); + if (stat.code != no_err) { + THROW_W_CODE_LOC(file, line, stat); + } + }; + if constexpr(std::is_same_v, void>) { + check_(); + fn(); + check_(); + } else { + check_(); + auto ret = fn(); + check_(); + return ret; + } + } + }; + #define OPENGL_CALL(expression) NB_OPENGL_CALL_MONITORING::run_expression(\ + __FILE__,\ + __LINE__,\ + [&]() {return expression;}\ + ) + #else + #define OPENGL_CALL(x) x + #endif // _NB_MONITOR_OPENGL_CALLS + +#endif // OPENGL_CALL + #endif // _NB_OGL_OBJECTS \ No newline at end of file diff --git a/engine/NBGraphics/include/NBGraphics/ProgramPipeline.hpp b/engine/NBGraphics/include/NBGraphics/ProgramPipeline.hpp index 229c7fe..9507bd4 100644 --- a/engine/NBGraphics/include/NBGraphics/ProgramPipeline.hpp +++ b/engine/NBGraphics/include/NBGraphics/ProgramPipeline.hpp @@ -78,8 +78,8 @@ class Shader : public OpenGLObject { for (int i=0; i < num_srcs; ++i) { src_ptrs[i] = _sources[i].data(); } - glShaderSource(_id, num_srcs, src_ptrs.data(), NULL); - glCompileShader(_id); + OPENGL_CALL(glShaderSource(_id, num_srcs, src_ptrs.data(), NULL)); + OPENGL_CALL(glCompileShader(_id)); _success = status(GL_COMPILE_STATUS); if (!_success) { WARN(log(), 0x0FE); @@ -88,14 +88,14 @@ class Shader : public OpenGLObject { virtual GLuint declare() override { if (!_id) { - _id = _id = glCreateShader(target); + _id = _id = OPENGL_CALL(glCreateShader(target)); } return _id; } virtual void remove() override { if (_id) { - glDeleteShader(_id); + OPENGL_CALL(glDeleteShader(_id)); } } @@ -113,7 +113,7 @@ class Program : public OpenGLObject { operator bool(); ~Program() { remove(); } virtual void bind() const override { - glUseProgram(_id); + OPENGL_CALL(glUseProgram(_id)); } virtual void unbind() const override { /* TODO: Some warning of some kind perhaps*/ } GLint status(GLenum) const; @@ -125,13 +125,13 @@ class Program : public OpenGLObject { GLint _success; virtual GLuint declare() override { if (!_id) { - _id = glCreateProgram(); + _id = OPENGL_CALL(glCreateProgram()); } return _id; } virtual void remove() override { if (_id) { - glDeleteProgram(_id); + OPENGL_CALL(glDeleteProgram(_id)); } } diff --git a/engine/NBGraphics/include/NBGraphics/Textures.hpp b/engine/NBGraphics/include/NBGraphics/Textures.hpp index 619deeb..07ffe0f 100644 --- a/engine/NBGraphics/include/NBGraphics/Textures.hpp +++ b/engine/NBGraphics/include/NBGraphics/Textures.hpp @@ -6,6 +6,8 @@ #include #include +/*! @file Textures.hpp */ + namespace nb { class TextureBuffer : public virtual Buffer { @@ -14,6 +16,9 @@ class TextureBuffer : public virtual Buffer { }; +/*! + @brief An OpenGL object that may be rendered to within a Framebuffer. +*/ class RenderTarget : public OpenGLObject { protected: using Base = OpenGLObject; @@ -23,11 +28,13 @@ class RenderTarget : public OpenGLObject { : Target(rhs.Target), Base(std::move(rhs)) {} public: - using Base::Base; using Base::id; const GLenum Target; }; +/*! + @brief An OpenGL Target object +*/ class Texture : public RenderTarget { protected: using Base = RenderTarget; @@ -35,7 +42,7 @@ class Texture : public RenderTarget { Texture(GLenum); virtual GLuint declare() override { if (!_id) { - glGenTextures(1, &_id); + OPENGL_CALL(glGenTextures(1, &_id)); } bind(); return _id; @@ -43,57 +50,69 @@ class Texture : public RenderTarget { virtual void remove() override { if (_id) { bind(); - glDeleteTextures(0, &_id); + OPENGL_CALL(glDeleteTextures(0, &_id)); } } public: - using Base::Base; using Base::id; using Base::Target; virtual void bind() const override { if (_id) { - glBindTexture(Target, _id); + OPENGL_CALL(glBindTexture(Target, _id)); } else { - THROW(OGLError( - OGLError::Codes::INVALID_OBJECT, + THROW(OpenGLObjectError( + OpenGLObjectError::Codes::INVALID_OBJECT, "w/ Texture" )); } } virtual void unbind() const override { - glBindTexture(Target, 0); + OPENGL_CALL(glBindTexture(Target, 0)); } template void parameter(GLenum param_, const T& val_); + void parameter(GLenum param_, const float& val_) { + declare(); + OPENGL_CALL( + glTexParameterf(Target, param_, val_) + ); + } void parameter(GLenum param_, const int& val_) { declare(); - glTexParameteri(_id, param_, val_); - } - void parameter(GLenum param_, const std::vector& val_) { - declare(); - glTexParameteriv(_id, param_, val_.data()); + OPENGL_CALL( + glTexParameteri(Target, param_, val_) + ); } void parameter(GLenum param_, const std::vector& val_) { declare(); - glTexParameterfv(_id, param_, val_.data()); + OPENGL_CALL( + glTexParameterfv(Target, param_, val_.data()) + ); + } + void parameter(GLenum param_, const std::vector& val_) { + declare(); + OPENGL_CALL( + glTexParameteriv(Target, param_, val_.data()) + ); } void parameter(GLenum param_, const std::vector& val_) { declare(); - glTexParameterIuiv(_id, param_, val_.data()); + OPENGL_CALL( + glTexParameterIuiv(Target, param_, val_.data()) + ); } void generateMipmaps() const { bind(); - glGenerateMipmap(Target); + OPENGL_CALL( + glGenerateMipmap(Target) + ); } }; -template -class ImageTexture; - template struct OGLPixelFormat; @@ -102,52 +121,110 @@ struct OGLPixelFormat>; template<> struct OGLPixelFormat> { - static constexpr GLenum glFormat = GL_RGB; + static constexpr GLenum glBase = GL_RGB; + static constexpr GLenum glFormat = GL_RGB8UI; static constexpr GLenum glData = GL_UNSIGNED_BYTE; }; template<> struct OGLPixelFormat> { - static constexpr GLenum glFormat = GL_RGBA; + static constexpr GLenum glBase = GL_RGBA; + static constexpr GLenum glFormat = GL_RGBA8UI; static constexpr GLenum glData = GL_UNSIGNED_BYTE; }; +template<> +struct OGLPixelFormat> { + static constexpr GLenum glBase = GL_RG; + static constexpr GLenum glFormat = GL_RG32F; + static constexpr GLenum glData = GL_FLOAT; +}; + +template +class Texture2D; + template -class ImageTexture> : public Texture { +class Texture2D> : public Texture { protected: using Texture::Texture; using PixelType = Pixel; public: using Texture::generateMipmaps; - ImageTexture() : Texture(GL_TEXTURE_2D) {} - ImageTexture(ImageTexture&& cpy) { + Texture2D() : Texture(GL_TEXTURE_2D) {} + Texture2D(Texture2D&& cpy) { *this = std::move(cpy); } - ImageTexture& operator=(ImageTexture&& rhs) { + Texture2D& operator=(Texture2D&& rhs) { return Texture::operator=(std::move(rhs)); } - void setImage(const Image& img, unsigned int layer) { + void setLayer(const Image& img, unsigned int layer) { using Format = OGLPixelFormat; declare(); - glTexImage2D( + auto data = img.data(); + OPENGL_CALL(glTexImage2D( Target, layer, Format::glFormat, img.width, img.height, 0, - Format::glFormat, + Format::glBase, Format::glData, - img.data() - ); + data ? data : nullptr + )); } - void setImage(const Image& img, bool generateMipmap=true) { - setImage(img, (unsigned int)0); + void setTexture(const Image& img, bool generateMipmap=true) { + setLayer(img, 0); if (generateMipmap) { generateMipmaps(); } } }; +template +class Texture1D; + +template +class Texture1D> : public Texture { + protected: + using Texture::Texture; + using PixelType = Pixel; + + public: + using Texture::generateMipmaps; + Texture1D() : Texture(GL_TEXTURE_1D) {} + Texture1D(Texture1D&& cpy) { + *this = std::move(cpy); + } + Texture1D& operator=(Texture1D&& rhs) { + return Texture::operator=(std::move(rhs)); + } + void setLayer(const Image& tex, unsigned int layer) { + if (tex.height != 1) { + THROW(Error<>( + Error<>::VALUE_ERROR, + "Image must be of height 1" + )); + } + using Format = OGLPixelFormat; + declare(); + auto data = tex.data(); + OPENGL_CALL(glTexImage1D( + Target, + layer, + Format::glFormat, + tex.width, + 0, + Format::glBase, + Format::glData, + data ? data : nullptr + )); + } + void setTexture(const Image& tex, bool generateMipmap=true) { + setLayer(tex, 0); + if (generateMipmap) { generateMipmaps(); } + } +}; + } // namespace nb #endif // _NB_TEXTURES \ No newline at end of file diff --git a/engine/NBGraphics/include/NBGraphics/VertexArray.hpp b/engine/NBGraphics/include/NBGraphics/VertexArray.hpp index a77b352..9688313 100644 --- a/engine/NBGraphics/include/NBGraphics/VertexArray.hpp +++ b/engine/NBGraphics/include/NBGraphics/VertexArray.hpp @@ -88,15 +88,17 @@ class VAO : public OpenGLObject { virtual void bind() const override { if(_id) { - glBindVertexArray(_id); + OPENGL_CALL(glBindVertexArray(_id)); } else { - THROW(OGLError( - OGLError::Codes::INVALID_OBJECT, + THROW(OpenGLObjectError( + OpenGLObjectError::Codes::INVALID_OBJECT, "w/ VertexArrayObject" )); } } - virtual void unbind() const override { glBindVertexArray(0); } + virtual void unbind() const override { + OPENGL_CALL(glBindVertexArray(0)); + } VertexAttributePointerList attributes() const; VertexAttributePointerList attributes(const VertexAttributePointerList&); @@ -114,13 +116,13 @@ class VAO : public OpenGLObject { if(_id) { disable(); bind(); - glDeleteVertexArrays(1, &_id); + OPENGL_CALL(glDeleteVertexArrays(1, &_id)); _id = 0; } } virtual GLuint declare() override { if (!_id) { - glGenVertexArrays(1, &_id); + OPENGL_CALL(glGenVertexArrays(1, &_id)); } bind(); return _id; diff --git a/engine/NBGraphics/include/NBGraphics/Window.hpp b/engine/NBGraphics/include/NBGraphics/Window.hpp index 8a2ea55..ec85d68 100644 --- a/engine/NBGraphics/include/NBGraphics/Window.hpp +++ b/engine/NBGraphics/include/NBGraphics/Window.hpp @@ -3,6 +3,7 @@ #define _NB_WINDOW #include +#include #include #include @@ -13,8 +14,8 @@ namespace nb { -class OpenGLError : public Error { - using Base = Error; +class GLFWError : public Error { + using Base = Error; public: using Base::Base; diff --git a/engine/NBGraphics/src/Buffers.cpp b/engine/NBGraphics/src/Buffers.cpp index 072177b..fa8bf09 100644 --- a/engine/NBGraphics/src/Buffers.cpp +++ b/engine/NBGraphics/src/Buffers.cpp @@ -2,7 +2,7 @@ namespace nb { -const std::unordered_map BufferTypes({ +const ConstantMap BufferTypes({ {GL_ARRAY_BUFFER, "GL_ARRAY_BUFFER"}, {GL_ELEMENT_ARRAY_BUFFER, "GL_ELEMENT_BUFFER"} }); @@ -22,10 +22,10 @@ Buffer::Buffer(Buffer&& rval) : Target(rval.Target) { Buffer& Buffer::operator=(Buffer&& rhs) { if (Target != rhs.Target) { - auto targ_name = BufferTypes.at(Target); - THROW(OGLError( - OGLError::Codes::INVALID_OBJECT, - "w/ BufferType "+targ_name+" != BufferType "+BufferTypes.at(rhs.Target) + auto targ_name = BufferTypes[Target]; + THROW(OpenGLObjectError( + OpenGLObjectError::Codes::INVALID_OBJECT, + "w/ BufferType "+targ_name+" != BufferType "+BufferTypes[Target] )); } OpenGLObject::operator=(std::move(rhs)); @@ -44,13 +44,13 @@ size_t Buffer::size() const { return _size; } ByteVector Buffer::data() const { bind(); ByteVector ret(_size); - glGetBufferSubData(Target, 0, _size, ret.data()); + OPENGL_CALL(glGetBufferSubData(Target, 0, _size, ret.data())); return ret; } void Buffer::data(const void* data_, size_t size_, GLenum usage_) { declare(); - glBufferData(Target, size_, data_, usage_); + OPENGL_CALL(glBufferData(Target, size_, data_, usage_)); _size = size_; _usage = usage_; } @@ -65,7 +65,7 @@ void Buffer::subdata(const void* data_, size_t size_, GLintptr offset_) { if (offset_+size_ <= _size) { THROW(BufferError(BufferError::Codes::DATA_OVERFLOW)); } - glBufferSubData(Target, offset_, size_, data_); + OPENGL_CALL(glBufferSubData(Target, offset_, size_, data_)); } void Buffer::subdata(const ByteVector& data_, GLintptr offset_) { diff --git a/engine/NBGraphics/src/FrameBuffers.cpp b/engine/NBGraphics/src/FrameBuffers.cpp index a0458df..17e88bf 100644 --- a/engine/NBGraphics/src/FrameBuffers.cpp +++ b/engine/NBGraphics/src/FrameBuffers.cpp @@ -11,7 +11,9 @@ const ErrorCodeMap FrameBufferError::ErrorMessages = { GLuint FrameBufferBase::declare() { if (!_id) { - glGenFramebuffers(1, &_id); + OPENGL_CALL( + glGenFramebuffers(1, &_id) + ); } bind(); return _id; @@ -20,7 +22,9 @@ GLuint FrameBufferBase::declare() { void FrameBufferBase::remove() { if (_id) { unbind(); - glDeleteFramebuffers(1, &_id); + OPENGL_CALL( + glDeleteFramebuffers(1, &_id) + ); _id=0; } } @@ -31,7 +35,9 @@ std::shared_ptr FrameBufferBase::detach(GLenum attch_) { bind(); auto ret = _attachments.at(attch_); _attachments.erase(attch_); - glFramebufferTexture(Target, attch_, 0, 0); + OPENGL_CALL( + glFramebufferTexture(Target, attch_, 0, 0) + ); return ret; } @@ -47,13 +53,13 @@ void FrameBufferBase::attach( "Cannot attach object to `GL_NONE`" )); } - glFramebufferTextureLayer( + OPENGL_CALL(glFramebufferTextureLayer( Target, attachment_, texture_->id(), level_, layer_ - ); + )); _attachments[attachment_] = texture_; } @@ -69,43 +75,72 @@ void FrameBufferBase::attach( )); } if (texTypeIs2D(texture_->Target)) { - glFramebufferTexture2D( + OPENGL_CALL(glFramebufferTexture2D( Target, attachment_, texture_->Target, texture_->id(), level_ - ); + )); } else { - glFramebufferTexture1D( + OPENGL_CALL(glFramebufferTexture1D( Target, attachment_, texture_->Target, texture_->id(), level_ - ); + )); } _attachments[attachment_] = texture_; } +void FrameBufferBase::attach( + GLenum attachment, + std::shared_ptr renderbuffer +) { + declare(); + if (attachment == GL_NONE) { + THROW(FrameBufferError(FrameBufferError::INVALID_VALUE, + "Cannot attach RenderBuffer to `GL_NONE`" + )); + } + OPENGL_CALL(glFramebufferRenderbuffer( + Target, + attachment, + GL_RENDERBUFFER, + renderbuffer->id() + )); + _attachments[attachment] = renderbuffer; +} + void FrameBufferBase::bind() const { if (_id) { - glBindFramebuffer(Target, _id); + OPENGL_CALL( + glBindFramebuffer(Target, _id) + ); } else { - THROW(OGLError( - OGLError::Codes::INVALID_OBJECT, + THROW(OpenGLObjectError( + OpenGLObjectError::Codes::INVALID_OBJECT, "w/ FrameBuffer" )); } } void FrameBufferBase::unbind() const { - glBindFramebuffer(Target, 0); + OPENGL_CALL( + glBindFramebuffer(Target, 0) + ); } GLenum FrameBufferBase::status() const { bind(); - return glCheckFramebufferStatus(Target); + return OPENGL_CALL( + glCheckFramebufferStatus(Target) + ); +} + +bool FrameBufferBase::complete() const { + return status() == GL_FRAMEBUFFER_COMPLETE; } FrameBufferBase::AttachmentMap FrameBufferBase::getAllBuffers() const { @@ -166,7 +201,7 @@ std::shared_ptr ReadFrameBuffer::setReadBuffer(GLenum attch_) { } } _location = attch_; - glReadBuffer(_location); + OPENGL_CALL(glReadBuffer(_location)); return getReadBuffer(); } @@ -222,7 +257,9 @@ WriteFrameBuffer::DrawTexVec WriteFrameBuffer::setWriteBuffers(const std::vector } } _locations = attchs_; - glDrawBuffers(_locations.size(), _locations.data()); + OPENGL_CALL( + glDrawBuffers(_locations.size(), _locations.data()) + ); return getWriteBuffers(); } @@ -230,7 +267,9 @@ std::shared_ptr WriteFrameBuffer::setWriteBuffer(GLenum attch_) { bind(); if (attch_ == GL_NONE) { std::vector tmp(_locations.size(), GL_NONE); - glDrawBuffers(tmp.size(), tmp.data()); + OPENGL_CALL( + glDrawBuffers(tmp.size(), tmp.data()) + ); _locations = {}; return nullptr; } @@ -241,13 +280,17 @@ std::shared_ptr WriteFrameBuffer::setWriteBuffer(GLenum attch_) { fRGBA WriteFrameBuffer::clearColorValue() const { bind(); float rgba[4]; - glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); + OPENGL_CALL( + glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba) + ); return fRGBA{rgba[0], rgba[1], rgba[2], rgba[3]}; } fRGBA WriteFrameBuffer::clearColorValue(const fRGBA& color) { declare(); - glClearColor(color.r, color.g, color.b, color.a); + OPENGL_CALL( + glClearColor(color.r, color.g, color.b, color.a) + ); return color; } @@ -258,32 +301,42 @@ fRGBA WriteFrameBuffer::clearColorValue(float r, float g, float b, float a) { double WriteFrameBuffer::clearDepthValue() const { bind(); double ret; - glGetDoublev(GL_DEPTH_CLEAR_VALUE, &ret); + OPENGL_CALL( + glGetDoublev(GL_DEPTH_CLEAR_VALUE, &ret) + ); return ret; } double WriteFrameBuffer::clearDepthValue(double d_) { declare(); - glClearDepth(d_); + OPENGL_CALL( + glClearDepth(d_) + ); return d_; } GLint WriteFrameBuffer::clearStencilValue() const { bind(); GLint ret; - glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &ret); + OPENGL_CALL( + glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &ret) + ); return ret; } GLint WriteFrameBuffer::clearStencilValue(GLint s_) { declare(); - glClearStencil(s_); + OPENGL_CALL( + glClearStencil(s_) + ); return s_; } void WriteFrameBuffer::clear(GLbitfield mask_) const { bind(); - glClear(mask_); + OPENGL_CALL( + glClear(mask_) + ); } void WriteFrameBuffer::clearDepth() const { @@ -292,7 +345,9 @@ void WriteFrameBuffer::clearDepth() const { void WriteFrameBuffer::clearDepth(float val_) const { bind(); - glClearBufferfv(GL_DEPTH, 0, &val_); + OPENGL_CALL( + glClearBufferfv(GL_DEPTH, 0, &val_) + ); } void WriteFrameBuffer::clearStencil() const { @@ -301,7 +356,9 @@ void WriteFrameBuffer::clearStencil() const { void WriteFrameBuffer::clearStencil(GLint val_) const { bind(); - glClearBufferiv(GL_STENCIL, 0, &val_); + OPENGL_CALL( + glClearBufferiv(GL_STENCIL, 0, &val_) + ); } void WriteFrameBuffer::clearDepthStencil() const { @@ -310,7 +367,9 @@ void WriteFrameBuffer::clearDepthStencil() const { void WriteFrameBuffer::clearDepthStencil(float d_, GLint s_) const { bind(); - glClearBufferfi(GL_DEPTH_STENCIL, 0, d_, s_); + OPENGL_CALL( + glClearBufferfi(GL_DEPTH_STENCIL, 0, d_, s_) + ); } FrameBuffer::FrameBuffer() diff --git a/engine/NBGraphics/src/OGLObjects.cpp b/engine/NBGraphics/src/OGLObjects.cpp index b5777a6..383c108 100644 --- a/engine/NBGraphics/src/OGLObjects.cpp +++ b/engine/NBGraphics/src/OGLObjects.cpp @@ -1,23 +1,65 @@ #include +#ifndef GLENUMSTRPAIR + #define GLENUMSTRPAIR(x) {x, #x} +#endif // GLENUMSTRPAIR + 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"}, - {OGLError::Codes::INVALID_OBJECT, "Attempting operation with invalid object"} +const std::string OpenGLObjectError::type = "nb::OpenGLObjectError"; +const ErrorCodeMap OpenGLObjectError::ErrorMessages = { + { OpenGLObjectError::Codes::UNDEFINED, "Error" }, + {OpenGLObjectError::Codes::HANGING_OBJECT, "Attempting to leave a hanging OpenGL object"}, + {OpenGLObjectError::Codes::INVALID_OBJECT, "Attempting operation with invalid object"} }; +const std::string OpenGLError::type = "nb::OpenGLError"; +const ErrorCodeMap OpenGLError::ErrorMessages = { + GLENUMSTRPAIR(GL_NO_ERROR), + GLENUMSTRPAIR(GL_INVALID_ENUM), + GLENUMSTRPAIR(GL_INVALID_ENUM), + GLENUMSTRPAIR(GL_INVALID_VALUE), + GLENUMSTRPAIR(GL_INVALID_OPERATION), + GLENUMSTRPAIR(GL_INVALID_FRAMEBUFFER_OPERATION), + GLENUMSTRPAIR(GL_OUT_OF_MEMORY), + GLENUMSTRPAIR(GL_STACK_UNDERFLOW), + GLENUMSTRPAIR(GL_STACK_OVERFLOW) +}; + +OpenGLError OpenGLError::status() { + return OpenGLError(glGetError()); +} + OpenGLObject::OpenGLObject(OpenGLObject&& rval) { *this = std::move(rval); } OpenGLObject& OpenGLObject::operator=(OpenGLObject&& rhs) { - if (_id) { THROW(OGLError(Codes::HANGING_OBJECT)); } + if (_id) { THROW(OpenGLObjectError(Codes::HANGING_OBJECT)); } _id = rhs._id; rhs._id = 0; return *this; } +const GLEnumTableType GLenumTable = { + GLENUMSTRPAIR(GL_DRAW_FRAMEBUFFER), + GLENUMSTRPAIR(GL_FRAMEBUFFER), + GLENUMSTRPAIR(GL_FRAMEBUFFER_COMPLETE), + GLENUMSTRPAIR(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT), + GLENUMSTRPAIR(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER), + GLENUMSTRPAIR(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS), + GLENUMSTRPAIR(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT), + GLENUMSTRPAIR(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE), + GLENUMSTRPAIR(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER), + GLENUMSTRPAIR(GL_FRAMEBUFFER_UNDEFINED), + GLENUMSTRPAIR(GL_FRAMEBUFFER_UNSUPPORTED), + GLENUMSTRPAIR(GL_READ_FRAMEBUFFER), + GLENUMSTRPAIR(GL_RG), + GLENUMSTRPAIR(GL_RG32F), + GLENUMSTRPAIR(GL_RGB), + GLENUMSTRPAIR(GL_RGB8UI), + GLENUMSTRPAIR(GL_RGBA8UI), + GLENUMSTRPAIR(GL_RGBA), +}; + } // namespace nb \ No newline at end of file diff --git a/engine/NBGraphics/src/ProgramPipeline.cpp b/engine/NBGraphics/src/ProgramPipeline.cpp index 6fbc77f..2dfe6e4 100644 --- a/engine/NBGraphics/src/ProgramPipeline.cpp +++ b/engine/NBGraphics/src/ProgramPipeline.cpp @@ -41,14 +41,14 @@ bool Shader::success() const { GLint Shader::status(GLenum parameter) const { GLint param = 0; - glGetShaderiv(_id, parameter, ¶m); + OPENGL_CALL(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_); + OPENGL_CALL(glGetShaderInfoLog(_id, logsize, NULL, log_)); std::string ret(log_, logsize); delete[] log_; return ret; @@ -57,9 +57,9 @@ std::string Shader::log() const { Program::Program(SharedVector shaders_) { declare(); for (auto shad_ptr : shaders_) { - glAttachShader(_id, shad_ptr->id()); + OPENGL_CALL(glAttachShader(_id, shad_ptr->id())); } - glLinkProgram(_id); + OPENGL_CALL(glLinkProgram(_id)); _success = status(GL_LINK_STATUS); if (!_success) { WARN(log(), 0x0FE); @@ -70,14 +70,14 @@ Program::operator bool() { return _success; } GLint Program::status(GLenum parameter) const { GLint param = 0; - glGetProgramiv(_id, parameter, ¶m); + OPENGL_CALL(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_); + OPENGL_CALL(glGetProgramInfoLog(_id, logsize, NULL, log_)); std::string ret(log_, logsize); delete[] log_; return ret; diff --git a/engine/NBGraphics/src/VertexArray.cpp b/engine/NBGraphics/src/VertexArray.cpp index 1740572..9a468d8 100644 --- a/engine/NBGraphics/src/VertexArray.cpp +++ b/engine/NBGraphics/src/VertexArray.cpp @@ -41,17 +41,17 @@ VertexAttributePointerList VAO::attributes(const VertexAttributePointerList& att _attrs = attrs_; bind(); for (auto attr_ptr : attrs_) { - glBindBuffer(GL_ARRAY_BUFFER, attr_ptr.buffer); + OPENGL_CALL(glBindBuffer(GL_ARRAY_BUFFER, attr_ptr.buffer)); GLuint idx = attr_ptr.index; - glVertexAttribPointer( + OPENGL_CALL(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); + )); + OPENGL_CALL(glEnableVertexAttribArray(idx)); } unbind(); return _attrs; @@ -70,7 +70,7 @@ void VAO::enable() const { if (_id) { bind(); for(auto attr_ptr : _attrs) { - glEnableVertexAttribArray(attr_ptr.index); + OPENGL_CALL(glEnableVertexAttribArray(attr_ptr.index)); } unbind(); } @@ -79,7 +79,7 @@ void VAO::enable() const { void VAO::enable(GLuint idx) const { if(_id) { bind(); - glEnableVertexAttribArray(attr(idx).index); + OPENGL_CALL(glEnableVertexAttribArray(attr(idx).index)); unbind(); } } @@ -88,7 +88,7 @@ void VAO::disable() const { if(_id) { bind(); for(auto attr_ptr : _attrs) { - glDisableVertexAttribArray(attr_ptr.index); + OPENGL_CALL(glDisableVertexAttribArray(attr_ptr.index)); } unbind(); } @@ -97,7 +97,7 @@ void VAO::disable() const { void VAO::disable(GLuint idx) const { if(_id) { bind(); - glDisableVertexAttribArray(attr(idx).index); + OPENGL_CALL(glDisableVertexAttribArray(attr(idx).index)); unbind(); } } @@ -120,7 +120,9 @@ VertexGroup& VertexGroup::operator=(VertexGroup&& rhs) { void VertexGroup::draw() const { bind(); - glDrawElements(primitive, _ebo->size(), _ebo->glslType(), 0); + OPENGL_CALL( + glDrawElements(primitive, _ebo->size(), _ebo->glslType(), 0) + ); } size_t VertexGroup::addBuffer(const VertexData& vertex_data_) { @@ -177,7 +179,7 @@ VertexDataVec VertexGroup::dropBuffers() { VertexData VertexGroup::dropBuffer(size_t idx) { if (idx >= _vertex_data.size()) { - THROW(Error(Error<>::INDEX_ERROR)); + THROW(Error(Error<>::OUT_OF_RANGE)); } VertexDataVec tmp; VertexData ret; diff --git a/engine/NBGraphics/src/Window.cpp b/engine/NBGraphics/src/Window.cpp index 53259f8..398d17f 100644 --- a/engine/NBGraphics/src/Window.cpp +++ b/engine/NBGraphics/src/Window.cpp @@ -16,13 +16,13 @@ static std::map defailt_window_hints = { #endif }; -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"} +using GLFWCodes = GLFWError::Codes; +const std::string GLFWError::type = "nb::GLFWError"; +const ErrorCodeMap GLFWError::ErrorMessages = { + {GLFWCodes::UNDEFINED, "Error"}, + {GLFWCodes::INIT_FAILED, "GLFW initialization failed"}, + {GLFWCodes::GLFW_INTIALIZED, "GLFW has already been initialized"}, + {GLFWCodes::GLAD_FAILED, "GLAD initialization failed"} }; using WindowErrorCodes = WindowError::Codes; @@ -44,7 +44,7 @@ int Window::getGLFWHint(int hint_key) { int Window::setGLFWHint(int hint_key, int hint_val) { if (Window::_glfw_init) { - THROW(OpenGLError(OpenGLErrorCodes::GLFW_INTIALIZED)); + THROW(GLFWError(GLFWCodes::GLFW_INTIALIZED)); } else { GLFWHints[hint_key] = hint_val; } @@ -74,7 +74,7 @@ Window::Window(const uint16_t x, const uint16_t y, const char* initName, GLFWmon Window::_glfw_init = true; } else { if (Window::StrictInitialization) { - THROW(OpenGLError(OpenGLErrorCodes::INIT_FAILED)); + THROW(GLFWError(GLFWCodes::INIT_FAILED)); } } } @@ -147,12 +147,14 @@ int Window::init() { if (!gladResponse) { Window::checkKillGLFW(); if (Window::StrictInitialization) { - THROW(OpenGLError(OpenGLErrorCodes::GLAD_FAILED)); + THROW(GLFWError(GLFWCodes::GLAD_FAILED)); } } _init = true; - glViewport(0, 0, windowSize[0], windowSize[1]); + OPENGL_CALL( + glViewport(0, 0, windowSize[0], windowSize[1]) + ); return gladResponse; } @@ -173,7 +175,9 @@ std::string Window::getName() const { void Window::resize(const std::array newSize) { windowSize = newSize; _aspect_ratio = float(newSize[0]) / float(newSize[1]); - glViewport(0, 0, windowSize[0], windowSize[1]); + OPENGL_CALL( + glViewport(0, 0, windowSize[0], windowSize[1]) + ); glfwSetWindowSize(window, windowSize[0], windowSize[1]); } diff --git a/engine/NBGraphics/tests/CMakeLists.txt b/engine/NBGraphics/tests/CMakeLists.txt index 6ee28e0..b5fd08e 100644 --- a/engine/NBGraphics/tests/CMakeLists.txt +++ b/engine/NBGraphics/tests/CMakeLists.txt @@ -4,21 +4,29 @@ if (NB_BUILD_TESTS) enable_testing() include(GoogleTest) + set(STBIMAGE_PATH ${NBENGINE_ROOT}/../stbi_image) + get_filename_component(STBIMAGE_PATH ${STBIMAGE_PATH} ABSOLUTE) + add_executable(TestWindow ./TestWindow.cpp ) target_link_libraries(TestWindow NBGraphics ) + target_include_directories(TestWindow + PRIVATE "${STBIMAGE_PATH}" + ) add_executable(TestImages ./testImages.cpp ) target_link_libraries(TestImages - NBCore NBGraphics GTest::gtest_main ) + target_include_directories(TestImages + PRIVATE "${STBIMAGE_PATH}" + ) gtest_discover_tests(TestImages) diff --git a/engine/NBGraphics/tests/TestWindow.cpp b/engine/NBGraphics/tests/TestWindow.cpp index cda33b0..97f433e 100644 --- a/engine/NBGraphics/tests/TestWindow.cpp +++ b/engine/NBGraphics/tests/TestWindow.cpp @@ -2,14 +2,16 @@ #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" +#include #include #include #include #include #include + int main() { - nb::logger.log("Howdy!"); + LOG("Howdy!"); nb::Window window(400, 400, "Hello!"); window.setWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); window.setWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); @@ -19,12 +21,12 @@ int main() { GL_VERTEX_SHADER, "#version 330 core\n" "layout (location = 0) in vec2 aPos;\n" - "layout (location = 1) in vec2 tPos;\n" - "out vec2 vPos;\n" + "out vec4 vColor;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);\n" - " vPos = tPos;\n" + " vec2 tmp = (aPos+vec2(1.0, 1.0))*0.5;\n" + " vColor = vec4(tmp.x, 0, tmp.y, 1.0);\n" "}\0" ); @@ -33,71 +35,41 @@ int main() { auto frag = std::make_shared( GL_FRAGMENT_SHADER, "#version 330 core\n" - "in vec2 vPos;\n" + "in vec4 vColor;\n" "out vec4 FragColor;\n" - "uniform sampler2D tex;\n" "void main()\n" "{\n" - " FragColor = texture(tex, vPos);\n" + " FragColor = vColor;\n" "}\n\0" ); LOG(frag->log()); nb::ByteVector data = nb::vectorToBytes({ - -0.5, -0.5, 0,0, - -0.5, 0.5, 0,1, - 0.5, 0.5, 1,1, - 0.5, -0.5, 1,0 + -0.5, -0.5, + 0, 0.5, + 0.5, -0.5 }); nb::Program prog({vert, frag}); prog.bind(); - std::vector indxs = {0, 1, 2, 0, 2, 3}; + std::vector indxs = {0, 1, 2}; nb::VertexGroup tri(data, { nb::VertexAttribute{ 2, GL_FLOAT, false, - {0, 16} + {0, 8} }, - nb::VertexAttribute{ - 2, - GL_FLOAT, - false, - {8, 16} - } }, indxs); - tri.bind(); - - int width, height, numChannels; - auto raw_img_data = stbi_load( - "./awesomeface.png", - &width, - &height, - &numChannels, - 0 - ); - LOG(numChannels); - using RGBA = nb::Pixel; - nb::ImageReference img(width, height, raw_img_data); - auto tex = nb::ImageTexture(); - tex.parameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); - tex.parameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); - tex.setImage(img); - tex.bind(); - tri.bind(); - LOG(img.at(256, 256).r); - stbi_image_free(raw_img_data); - LOG(prog.log()); GLFWwindow* window_ptr = window.getWindow(); while(!glfwWindowShouldClose(window_ptr)) { - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + OPENGL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f)); + OPENGL_CALL(glClear(GL_COLOR_BUFFER_BIT)); tri.draw(); glfwPollEvents(); glfwSwapBuffers(window_ptr);