From f4b194f6fed0396570c3b82127fbc77269de9494 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 31 May 2012 18:18:28 +0200 Subject: [PATCH] Fixed rendering with OpenGL core profile Added (automatic) support of Vertex Arrays Objects (VAO) to fix rendering with an OpenGL core profile (OpenGL 3.2 require the use of VAOs) Added level check to NzImage::GetDepth/Height/Size/Width Fixed occlussion query support not correctly setted --- include/Nazara/Prerequesites.hpp | 26 ++-- include/Nazara/Renderer/OpenGL.hpp | 6 +- include/Nazara/Renderer/Renderer.hpp | 10 +- src/Nazara/Renderer/GLSLShader.cpp | 57 +-------- src/Nazara/Renderer/GLSLShader.hpp | 2 - src/Nazara/Renderer/OpenGL.cpp | 27 +++- src/Nazara/Renderer/Renderer.cpp | 177 +++++++++++++++++++++------ src/Nazara/Renderer/ShaderImpl.hpp | 3 - src/Nazara/Utility/Image.cpp | 34 ++++- 9 files changed, 220 insertions(+), 122 deletions(-) diff --git a/include/Nazara/Prerequesites.hpp b/include/Nazara/Prerequesites.hpp index ff66261cc..2a3fe5140 100644 --- a/include/Nazara/Prerequesites.hpp +++ b/include/Nazara/Prerequesites.hpp @@ -62,24 +62,18 @@ #if NAZARA_CORE_WINDOWS_VISTA // Version de Windows minimale : Vista - #if defined(_WIN32_WINNT) - #if _WIN32_WINNT < 0x0600 - #undef _WIN32_WINNT - #define _WIN32_WINNT 0x0600 - #endif - #else - #define _WIN32_WINNT 0x0600 + #define NAZARA_WINNT 0x0600 + #else + #define NAZARA_WINNT 0x0501 + #endif + + #if defined(_WIN32_WINNT) + #if _WIN32_WINNT < NAZARA_WINNT + #undef _WIN32_WINNT + #define _WIN32_WINNT NAZARA_WINNT #endif #else - // Version de Windows minimale : XP - #if defined(_WIN32_WINNT) - #if _WIN32_WINNT < 0x0501 - #undef _WIN32_WINNT - #define _WIN32_WINNT 0x0501 - #endif - #else - #define _WIN32_WINNT 0x0501 - #endif + #define _WIN32_WINNT NAZARA_WINNT #endif #endif #elif defined(linux) || defined(__linux) diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index fc229991f..832d558a6 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -35,8 +35,9 @@ class NAZARA_API NzOpenGL { AnisotropicFilter, FP64, - Framebuffer_Object, + FrameBufferObject, Texture3D, + VertexArrayObject, Count }; @@ -56,6 +57,7 @@ NAZARA_API extern PFNGLBINDBUFFERPROC glBindBuffer; NAZARA_API extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; NAZARA_API extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; NAZARA_API extern PFNGLBINDTEXTUREPROC glBindTexture; +NAZARA_API extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; NAZARA_API extern PFNGLBLENDFUNCPROC glBlendFunc; NAZARA_API extern PFNGLBUFFERDATAPROC glBufferData; NAZARA_API extern PFNGLBUFFERSUBDATAPROC glBufferSubData; @@ -76,6 +78,7 @@ NAZARA_API extern PFNGLDELETEQUERIESPROC glDeleteQueries; NAZARA_API extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; NAZARA_API extern PFNGLDELETESHADERPROC glDeleteShader; NAZARA_API extern PFNGLDELETETEXTURESPROC glDeleteTextures; +NAZARA_API extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; NAZARA_API extern PFNGLDEPTHFUNCPROC glDepthFunc; NAZARA_API extern PFNGLDEPTHMASKPROC glDepthMask; NAZARA_API extern PFNGLDISABLEPROC glDisable; @@ -96,6 +99,7 @@ NAZARA_API extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; NAZARA_API extern PFNGLGENQUERIESPROC glGenQueries; NAZARA_API extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; NAZARA_API extern PFNGLGENTEXTURESPROC glGenTextures; +NAZARA_API extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; NAZARA_API extern PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv; NAZARA_API extern PFNGLGETERRORPROC glGetError; NAZARA_API extern PFNGLGETINTEGERVPROC glGetIntegerv; diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index 6b509ece0..86cee1cba 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -8,6 +8,8 @@ #define NAZARA_RENDERER_HPP #include +#include +#include #define NazaraRenderer NzRenderer::Instance() @@ -45,6 +47,7 @@ enum nzRendererClear }; class NzColor; +class NzContext; class NzIndexBuffer; class NzRenderTarget; class NzShader; @@ -86,8 +89,11 @@ class NAZARA_API NzRenderer static bool IsInitialized(); private: - bool UpdateVertexBuffer(); + bool UpdateStates(); + typedef std::tuple VAO_Key; + + std::map m_vaos; const NzIndexBuffer* m_indexBuffer; NzRenderTarget* m_target; NzShader* m_shader; @@ -95,7 +101,7 @@ class NAZARA_API NzRenderer const NzVertexBuffer* m_vertexBuffer; const NzVertexDeclaration* m_vertexDeclaration; bool m_capabilities[nzRendererCap_Count]; - bool m_vertexBufferUpdated; + bool m_statesUpdated; static NzRenderer* s_instance; static bool s_initialized; diff --git a/src/Nazara/Renderer/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index eda9240e8..af9403f89 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -6,14 +6,13 @@ #include #include #include -#include -#include #include #include namespace { - nzUInt8 attribIndex[] = + ///FIXME: Déclaré deux fois (ici et dans Renderer.cpp) + const nzUInt8 attribIndex[] = { 2, // nzElementUsage_Diffuse 1, // nzElementUsage_Normal @@ -27,32 +26,6 @@ namespace GL_GEOMETRY_SHADER, // nzShaderType_Geometry GL_VERTEX_SHADER // nzShaderType_Vertex }; - - const nzUInt8 size[] = - { - 4, // nzElementType_Color - 1, // nzElementType_Double1 - 2, // nzElementType_Double2 - 3, // nzElementType_Double3 - 4, // nzElementType_Double4 - 1, // nzElementType_Float1 - 2, // nzElementType_Float2 - 3, // nzElementType_Float3 - 4 // nzElementType_Float4 - }; - - const GLenum type[] = - { - GL_UNSIGNED_BYTE, // nzElementType_Color - GL_DOUBLE, // nzElementType_Double1 - GL_DOUBLE, // nzElementType_Double2 - GL_DOUBLE, // nzElementType_Double3 - GL_DOUBLE, // nzElementType_Double4 - GL_FLOAT, // nzElementType_Float1 - GL_FLOAT, // nzElementType_Float2 - GL_FLOAT, // nzElementType_Float3 - GL_FLOAT // nzElementType_Float4 - }; } NzGLSLShader::NzGLSLShader(NzShader* parent) : @@ -331,29 +304,3 @@ void NzGLSLShader::Unlock() const if (--m_lockedLevel == 0 && m_lockedPrevious != m_program) glUseProgram(m_lockedPrevious); } - -bool NzGLSLShader::UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration) -{ - vertexBuffer->GetBuffer()->GetImpl()->Bind(); - const nzUInt8* buffer = reinterpret_cast(vertexBuffer->GetBufferPtr()); - - ///FIXME: Améliorer les déclarations pour permettre de faire ça plus simplement - for (int i = 0; i < 12; ++i) // Solution temporaire, à virer - glDisableVertexAttribArray(i); // Chaque itération tue un chaton :( - - unsigned int stride = vertexDeclaration->GetStride(); - unsigned int elementCount = vertexDeclaration->GetElementCount(); - for (unsigned int i = 0; i < elementCount; ++i) - { - const NzVertexDeclaration::Element* element = vertexDeclaration->GetElement(i); - glEnableVertexAttribArray(attribIndex[element->usage]+element->usageIndex); - glVertexAttribPointer(attribIndex[element->usage]+element->usageIndex, - size[element->type], - type[element->type], - (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, - stride, - &buffer[element->offset]); - } - - return true; -} diff --git a/src/Nazara/Renderer/GLSLShader.hpp b/src/Nazara/Renderer/GLSLShader.hpp index 86efaabaf..653955999 100644 --- a/src/Nazara/Renderer/GLSLShader.hpp +++ b/src/Nazara/Renderer/GLSLShader.hpp @@ -47,8 +47,6 @@ class NzGLSLShader : public NzShaderImpl void Unlock() const; private: - bool UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration); - mutable std::map m_idCache; mutable GLuint m_lockedPrevious; GLuint m_program; diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index e76b224c6..3dde42994 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -314,7 +314,7 @@ bool NzOpenGL::Initialize() } } - // Framebuffer_Object + // FrameBufferObject try { glBindFramebuffer = reinterpret_cast(LoadEntry("glBindFramebuffer")); @@ -329,7 +329,7 @@ bool NzOpenGL::Initialize() glGenRenderbuffers = reinterpret_cast(LoadEntry("glGenRenderbuffers")); glRenderbufferStorage = reinterpret_cast(LoadEntry("glRenderbufferStorage")); - openGLextensions[NzOpenGL::Framebuffer_Object] = true; + openGLextensions[NzOpenGL::FrameBufferObject] = true; } catch (const std::exception& e) { @@ -352,7 +352,7 @@ bool NzOpenGL::Initialize() glGenRenderbuffers = reinterpret_cast(LoadEntry("glGenRenderbuffersEXT")); glRenderbufferStorage = reinterpret_cast(LoadEntry("glRenderbufferStorageEXT")); - openGLextensions[NzOpenGL::Framebuffer_Object] = true; + openGLextensions[NzOpenGL::FrameBufferObject] = true; } catch (const std::exception& e) { @@ -377,8 +377,24 @@ bool NzOpenGL::Initialize() } } - /****************************************Contextes****************************************/ + // VertexArrayObject + if (openGLversion >= 300 || IsSupported("GL_ARB_vertex_array_object")) + { + try + { + glBindVertexArray = reinterpret_cast(LoadEntry("glBindVertexArray", false)); + glDeleteVertexArrays = reinterpret_cast(LoadEntry("glDeleteVertexArrays", false)); + glGenVertexArrays = reinterpret_cast(LoadEntry("glGenVertexArrays", false)); + openGLextensions[NzOpenGL::VertexArrayObject] = true; + } + catch (const std::exception& e) + { + NazaraError("Failed to load ARB_vertex_array_object: " + NzString(e.what())); + } + } + + /****************************************Contextes****************************************/ NzContextParameters::defaultMajorVersion = openGLversion/100; NzContextParameters::defaultMinorVersion = (openGLversion%100)/10; @@ -427,6 +443,7 @@ PFNGLBINDBUFFERPROC glBindBuffer = nullptr; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr; PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr; PFNGLBINDTEXTUREPROC glBindTexture = nullptr; +PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr; PFNGLBLENDFUNCPROC glBlendFunc = nullptr; PFNGLBUFFERDATAPROC glBufferData = nullptr; PFNGLBUFFERSUBDATAPROC glBufferSubData = nullptr; @@ -447,6 +464,7 @@ PFNGLDELETEQUERIESPROC glDeleteQueries = nullptr; PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr; PFNGLDELETESHADERPROC glDeleteShader = nullptr; PFNGLDELETETEXTURESPROC glDeleteTextures = nullptr; +PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr; PFNGLDEPTHFUNCPROC glDepthFunc = nullptr; PFNGLDEPTHMASKPROC glDepthMask = nullptr; PFNGLDISABLEPROC glDisable = nullptr; @@ -467,6 +485,7 @@ PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr; PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr; PFNGLGENQUERIESPROC glGenQueries = nullptr; PFNGLGENTEXTURESPROC glGenTextures = nullptr; +PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr; PFNGLGETERRORPROC glGetError = nullptr; PFNGLGETINTEGERVPROC glGetIntegerv = nullptr; diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 6daae067c..7de849aff 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -14,13 +14,23 @@ #include #include #include +#include #include #include #include namespace { - GLenum openglPrimitive[] = { + const nzUInt8 attribIndex[] = + { + 2, // nzElementUsage_Diffuse + 1, // nzElementUsage_Normal + 0, // nzElementUsage_Position + 3, // nzElementUsage_Tangent + 4 // nzElementUsage_TexCoord + }; + + const GLenum openglPrimitive[] = { GL_LINES, // nzPrimitiveType_LineList, GL_LINE_STRIP, // nzPrimitiveType_LineStrip, GL_POINTS, // nzPrimitiveType_PointList, @@ -28,6 +38,32 @@ namespace GL_TRIANGLE_STRIP, // nzPrimitiveType_TriangleStrip, GL_TRIANGLE_FAN // nzPrimitiveType_TriangleFan }; + + const nzUInt8 openglSize[] = + { + 4, // nzElementType_Color + 1, // nzElementType_Double1 + 2, // nzElementType_Double2 + 3, // nzElementType_Double3 + 4, // nzElementType_Double4 + 1, // nzElementType_Float1 + 2, // nzElementType_Float2 + 3, // nzElementType_Float3 + 4 // nzElementType_Float4 + }; + + const GLenum openglType[] = + { + GL_UNSIGNED_BYTE, // nzElementType_Color + GL_DOUBLE, // nzElementType_Double1 + GL_DOUBLE, // nzElementType_Double2 + GL_DOUBLE, // nzElementType_Double3 + GL_DOUBLE, // nzElementType_Double4 + GL_FLOAT, // nzElementType_Float1 + GL_FLOAT, // nzElementType_Float2 + GL_FLOAT, // nzElementType_Float3 + GL_FLOAT // nzElementType_Float4 + }; } NzRenderer::NzRenderer() : @@ -36,7 +72,7 @@ m_target(nullptr), m_shader(nullptr), m_vertexBuffer(nullptr), m_vertexDeclaration(nullptr), -m_vertexBufferUpdated(false) +m_statesUpdated(false) { #if NAZARA_RENDERER_SAFE if (s_instance) @@ -91,11 +127,11 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f } #endif - if (!m_vertexBufferUpdated) + if (!m_statesUpdated) { - if (!UpdateVertexBuffer()) + if (!UpdateStates()) { - NazaraError("Failed to update vertex buffer"); + NazaraError("Failed to update states"); return; } } @@ -127,11 +163,11 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount) { - if (!m_vertexBufferUpdated) + if (!m_statesUpdated) { - if (!UpdateVertexBuffer()) + if (!UpdateStates()) { - NazaraError("Failed to update vertex buffer"); + NazaraError("Failed to update states"); return; } } @@ -191,7 +227,7 @@ bool NzRenderer::Initialize() m_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(NzOpenGL::FP64); m_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5 m_capabilities[nzRendererCap_MultipleRenderTargets] = true; // Natif depuis OpenGL 2.0 - m_capabilities[nzRendererCap_OcclusionQuery] = // Natif depuis OpenGL 1.5 + m_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5 m_capabilities[nzRendererCap_SoftwareBuffer] = NzOpenGL::GetVersion() <= 300; // Déprécié en OpenGL 3 m_capabilities[nzRendererCap_Texture3D] = NzOpenGL::IsSupported(NzOpenGL::Texture3D); m_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3 @@ -260,12 +296,11 @@ void NzRenderer::SetClearStencil(unsigned int value) bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer) { - if (indexBuffer == m_indexBuffer) - return true; - - // OpenGL ne nécessite pas de débinder un index buffer pour ne pas l'utiliser - if (indexBuffer) - indexBuffer->GetBuffer()->m_impl->Bind(); + if (indexBuffer != m_indexBuffer) + { + m_indexBuffer = indexBuffer; + m_statesUpdated = false; + } return true; } @@ -292,7 +327,6 @@ bool NzRenderer::SetShader(NzShader* shader) } m_shader = shader; - m_vertexBufferUpdated = false; } else if (m_shader) { @@ -339,24 +373,22 @@ bool NzRenderer::SetTarget(NzRenderTarget* target) bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer) { - if (m_vertexBuffer == vertexBuffer) - return true; - - if (m_vertexBuffer && vertexBuffer) + if (m_vertexBuffer != vertexBuffer) { - // Si l'ancien buffer et le nouveau sont hardware, pas besoin de mettre à jour la déclaration - if (!m_vertexBuffer->IsHardware() || !vertexBuffer->IsHardware()) - m_vertexBufferUpdated = false; + m_vertexBuffer = vertexBuffer; + m_statesUpdated = false; } - m_vertexBuffer = vertexBuffer; return true; } bool NzRenderer::SetVertexDeclaration(const NzVertexDeclaration* vertexDeclaration) { - m_vertexDeclaration = vertexDeclaration; - m_vertexBufferUpdated = false; + if (m_vertexDeclaration != vertexDeclaration) + { + m_vertexDeclaration = vertexDeclaration; + m_statesUpdated = false; + } return true; } @@ -371,10 +403,17 @@ void NzRenderer::Uninitialize() } #endif - NzOpenGL::Uninitialize(); - s_initialized = false; + // Libération des VAOs + for (auto it = m_vaos.begin(); it != m_vaos.end(); ++it) + { + GLuint vao = it->second; + glDeleteVertexArrays(1, &vao); + } + + NzOpenGL::Uninitialize(); + if (m_utilityModule) { delete m_utilityModule; @@ -397,15 +436,9 @@ bool NzRenderer::IsInitialized() return s_initialized; } -bool NzRenderer::UpdateVertexBuffer() +bool NzRenderer::UpdateStates() { #if NAZARA_RENDERER_SAFE - if (!m_shader) - { - NazaraError("No shader"); - return false; - } - if (!m_vertexBuffer) { NazaraError("No vertex buffer"); @@ -419,10 +452,78 @@ bool NzRenderer::UpdateVertexBuffer() } #endif - if (!m_shader->m_impl->UpdateVertexBuffer(m_vertexBuffer, m_vertexDeclaration)) - return false; + static const bool vaoSupported = NzOpenGL::IsSupported(NzOpenGL::VertexArrayObject); + bool update; + GLuint vao; - m_vertexBufferUpdated = true; + // Si les VAOs sont supportés, on entoure nos appels par ceux-ci + if (vaoSupported) + { + // On recherche si un VAO existe déjà avec notre configuration + // Note: Les VAOs ne sont pas partagés entre les contextes, ils font donc partie de notre configuration + + auto key = std::make_tuple(NzContext::GetCurrent(), m_indexBuffer, m_vertexBuffer, m_vertexDeclaration); + auto it = m_vaos.find(key); + if (it == m_vaos.end()) + { + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + m_vaos.insert(std::make_pair(key, static_cast(vao))); + + update = true; + } + else + { + // Notre VAO existe déjà, il est donc inutile de le reprogrammer + vao = it->second; + + update = false; + } + } + else + update = true; // Fallback si les VAOs ne sont pas supportés + + if (update) + { + m_vertexBuffer->GetBuffer()->GetImpl()->Bind(); + + const nzUInt8* buffer = reinterpret_cast(m_vertexBuffer->GetBufferPtr()); + + ///FIXME: Améliorer les déclarations pour permettre de faire ça plus simplement + for (int i = 0; i < 12; ++i) // Solution temporaire, à virer + glDisableVertexAttribArray(i); // Chaque itération tue un chaton :( + + unsigned int stride = m_vertexDeclaration->GetStride(); + unsigned int elementCount = m_vertexDeclaration->GetElementCount(); + for (unsigned int i = 0; i < elementCount; ++i) + { + const NzVertexDeclaration::Element* element = m_vertexDeclaration->GetElement(i); + + glEnableVertexAttribArray(attribIndex[element->usage]+element->usageIndex); + glVertexAttribPointer(attribIndex[element->usage]+element->usageIndex, + openglSize[element->type], + openglType[element->type], + (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, + stride, + &buffer[element->offset]); + } + + if (m_indexBuffer) + m_indexBuffer->GetBuffer()->GetImpl()->Bind(); + } + + if (vaoSupported) + { + // Si nous venons de définir notre VAO, nous devons le débinder pour indiquer la fin de sa construction + if (update) + glBindVertexArray(0); + + // Nous (re)bindons le VAO pour définir les attributs de vertice + glBindVertexArray(vao); + } + + m_statesUpdated = true; return true; } diff --git a/src/Nazara/Renderer/ShaderImpl.hpp b/src/Nazara/Renderer/ShaderImpl.hpp index 9d30cedbc..b5b1316ec 100644 --- a/src/Nazara/Renderer/ShaderImpl.hpp +++ b/src/Nazara/Renderer/ShaderImpl.hpp @@ -47,9 +47,6 @@ class NzShaderImpl virtual void Unbind() = 0; virtual void Unlock() const = 0; - - protected: - virtual bool UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration) = 0; }; #endif // NAZARA_SHADERIMPL_HPP diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 4e80eae9a..5e76b5ce3 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -271,6 +271,14 @@ const nzUInt8* NzImage::GetConstPixels(nzUInt8 level) const unsigned int NzImage::GetDepth(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return std::max(m_sharedImage->depth/(1 << level), 1U); } @@ -281,6 +289,14 @@ nzPixelFormat NzImage::GetFormat() const unsigned int NzImage::GetHeight(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return std::max(m_sharedImage->height/(1 << level), 1U); } @@ -422,6 +438,14 @@ unsigned int NzImage::GetSize() const unsigned int NzImage::GetSize(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return (std::max(m_sharedImage->width/(1 << level), 1U)) * (std::max(m_sharedImage->height/(1 << level), 1U)) * ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::min(m_sharedImage->depth/(1 << level), 1U)) * @@ -435,6 +459,14 @@ nzImageType NzImage::GetType() const unsigned int NzImage::GetWidth(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return std::max(m_sharedImage->width/(1 << level), 1U); } @@ -905,4 +937,4 @@ void NzImage::ReleaseImage() m_sharedImage = &emptyImage; } -NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_Undefined, 0, nullptr, 0, 0, 0); +NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_Undefined, 1, nullptr, 0, 0, 0);