Added NzTexture

Added levelCount parameter to NzImageParams
Added NzPixelFormat::HasAlpha
Reformatted OpenGL debug messages
This commit is contained in:
Lynix 2012-06-05 10:54:06 +02:00
parent 49353cb636
commit a176648265
19 changed files with 1807 additions and 64 deletions

View File

@ -38,6 +38,7 @@ class NAZARA_API NzOpenGL
FP64,
FrameBufferObject,
Texture3D,
TextureCompression_s3tc,
TextureStorage,
VertexArrayObject,
@ -120,6 +121,8 @@ NAZARA_API extern PFNGLGETSHADERSOURCEPROC glGetShaderSource;
NAZARA_API extern PFNGLGETSTRINGPROC glGetString;
NAZARA_API extern PFNGLGETSTRINGIPROC glGetStringi;
NAZARA_API extern PFNGLGETTEXIMAGEPROC glGetTexImage;
NAZARA_API extern PFNGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv;
NAZARA_API extern PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv;
NAZARA_API extern PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv;
NAZARA_API extern PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv;
NAZARA_API extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;

View File

@ -32,6 +32,7 @@ enum nzShaderType
class NzRenderer;
class NzShaderImpl;
class NzTexture;
class NAZARA_API NzShader : public NzResource, NzNonCopyable
{
@ -65,6 +66,7 @@ class NAZARA_API NzShader : public NzResource, NzNonCopyable
bool SendInteger(const NzString& name, int value);
bool SendMatrix(const NzString& name, const NzMatrix4d& matrix);
bool SendMatrix(const NzString& name, const NzMatrix4f& matrix);
bool SendTexture(const NzString& name, NzTexture* texture);
void Unlock();

View File

@ -0,0 +1,98 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_TEXTURE_HPP
#define NAZARA_TEXTURE_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/NonCopyable.hpp>
#include <Nazara/Utility/Image.hpp>
#include <Nazara/Utility/PixelFormat.hpp>
enum nzTextureFilter
{
nzTextureFilter_Bilinear,
nzTextureFilter_Nearest,
nzTextureFilter_Trilinear,
nzTextureFilter_Unknown
};
enum nzTextureWrap
{
nzTextureWrap_Clamp,
nzTextureWrap_Repeat,
nzTextureWrap_Unknown
};
class NzRenderWindow; ///TODO: Screenshot
struct NzTextureImpl;
class NAZARA_API NzTexture : public NzResource, NzNonCopyable
{
friend class NzShader;
public:
NzTexture();
explicit NzTexture(const NzImage& image);
~NzTexture();
bool Bind();
bool Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, nzUInt8 levelCount = 1, bool lock = false);
void Destroy();
bool Download(NzImage* image) const;
bool EnableMipmapping(bool enable);
unsigned int GetAnisotropyLevel() const;
nzUInt8 GetBPP() const;
unsigned int GetDepth() const;
nzTextureFilter GetFilterMode() const;
nzPixelFormat GetFormat() const;
unsigned int GetHeight() const;
nzImageType GetType() const;
unsigned int GetWidth() const;
nzTextureWrap GetWrapMode() const;
bool IsCompressed() const;
bool IsCubemap() const;
bool IsValid() const;
bool LoadFromFile(const NzString& filePath, const NzImageParams& params = NzImageParams());
bool LoadFromImage(const NzImage& image);
bool LoadFromMemory(const void* data, std::size_t size, const NzImageParams& params = NzImageParams());
bool LoadFromStream(NzInputStream& stream, const NzImageParams& params = NzImageParams());
bool Lock();
bool SetAnisotropyLevel(unsigned int anistropyLevel);
bool SetFilterMode(nzTextureFilter filter);
bool SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel);
bool SetWrapMode(nzTextureWrap wrap);
bool Update(const NzImage& image, nzUInt8 level = 0);
bool Update(const NzImage& image, const NzRectui& rect, unsigned int z = 0, nzUInt8 level = 0);
//bool Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level = 0);
bool Update(const nzUInt8* pixels, nzUInt8 level = 0);
bool Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z = 0, nzUInt8 level = 0);
//bool Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level = 0);
bool UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 level = 0);
bool UpdateFace(nzCubemapFace face, const NzImage& image, const NzRectui& rect, nzUInt8 level = 0);
bool UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 level = 0);
bool UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, nzUInt8 level = 0);
void Unlock();
static unsigned int GetValidSize(unsigned int size);
static bool IsFormatSupported(nzPixelFormat format);
static bool IsTypeSupported(nzImageType type);
private:
NzTextureImpl* m_impl;
};
#endif // NAZARA_TEXTURE_HPP

View File

@ -31,18 +31,22 @@ enum nzImageType
nzImageType_1D,
nzImageType_2D,
nzImageType_3D,
nzImageType_Cubemap
nzImageType_Cubemap,
nzImageType_Count
};
struct NzImageParams
{
// GCC 4.7 je te veux
NzImageParams() :
loadFormat(nzPixelFormat_Undefined)
loadFormat(nzPixelFormat_Undefined),
levelCount(0)
{
}
nzPixelFormat loadFormat;
nzUInt8 levelCount;
bool IsValid() const
{

View File

@ -53,6 +53,8 @@ class NzPixelFormat
static nzUInt8 GetBPP(nzPixelFormat format);
static bool HasAlpha(nzPixelFormat format);
static bool IsCompressed(nzPixelFormat format);
static bool IsConversionSupported(nzPixelFormat srcFormat, nzPixelFormat dstFormat);
static bool IsValid(nzPixelFormat format);
@ -65,7 +67,7 @@ class NzPixelFormat
static bool Initialize();
static void Uninitialize();
static ConvertFunction s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count];
static NAZARA_API ConvertFunction s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count];
};
#include <Nazara/Utility/PixelFormat.inl>

View File

@ -139,6 +139,24 @@ inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format)
return 0;
}
inline bool NzPixelFormat::HasAlpha(nzPixelFormat format)
{
switch (format)
{
case nzPixelFormat_BGRA8:
case nzPixelFormat_DXT3:
case nzPixelFormat_DXT5:
case nzPixelFormat_LA8:
case nzPixelFormat_RGB5A1:
case nzPixelFormat_RGBA4:
case nzPixelFormat_RGBA8:
return true;
default:
return false;
}
}
inline bool NzPixelFormat::IsCompressed(nzPixelFormat format)
{
switch (format)

View File

@ -31,7 +31,8 @@ namespace
NzStringStream ss;
ss << "OpenGL debug message (ID: 0x" << NzString::Number(id, 16) << "):\n";
ss << "-Source: ";
ss << "Sent by context: " << userParam;
ss << "\n-Source: ";
switch (source)
{
case GL_DEBUG_SOURCE_API_ARB:
@ -121,8 +122,7 @@ namespace
}
ss << '\n';
ss << "Message: " << message;
ss << "\n\nSent by context: " << userParam;
ss << "Message: " << message << '\n';
NazaraNotice(ss);
}

View File

@ -6,6 +6,8 @@
#include <Nazara/Renderer/GLSLShader.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/String.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Renderer/VertexDeclaration.hpp>
#include <Nazara/Renderer/Debug.hpp>
@ -26,6 +28,9 @@ namespace
GL_GEOMETRY_SHADER, // nzShaderType_Geometry
GL_VERTEX_SHADER // nzShaderType_Vertex
};
GLuint lockedPrevious = 0;
nzUInt8 lockedLevel = 0;
}
NzGLSLShader::NzGLSLShader(NzShader* parent) :
@ -39,9 +44,24 @@ NzGLSLShader::~NzGLSLShader()
bool NzGLSLShader::Bind()
{
#if NAZARA_RENDERER_SAFE
if (lockedLevel > 0)
{
NazaraError("Cannot bind shader while a shader is locked");
return false;
}
#endif
glUseProgram(m_program);
return true; ///FIXME: Comment détecter une erreur d'OpenGL sans ralentir le programme ?
for (auto it = m_textures.begin(); it != m_textures.end(); ++it)
{
glActiveTexture(GL_TEXTURE0 + it->second.unit);
if (!it->second.texture->Bind())
NazaraWarning("Failed to bind texture");
}
return true;
}
bool NzGLSLShader::Compile()
@ -106,6 +126,8 @@ bool NzGLSLShader::Create()
for (int i = 0; i < nzShaderType_Count; ++i)
m_shaders[i] = 0;
m_textureFreeID = 0;
return true;
}
@ -218,16 +240,16 @@ bool NzGLSLShader::Load(nzShaderType type, const NzString& source)
}
}
bool NzGLSLShader::Lock() const
bool NzGLSLShader::Lock()
{
if (m_lockedLevel++ == 0)
if (lockedLevel++ == 0)
{
GLint previous;
glGetIntegerv(GL_CURRENT_PROGRAM, &previous);
m_lockedPrevious = previous;
lockedPrevious = previous;
if (m_lockedPrevious != m_program)
if (lockedPrevious != m_program)
glUseProgram(m_program);
}
@ -288,19 +310,72 @@ bool NzGLSLShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix)
return true;
}
bool NzGLSLShader::SendTexture(const NzString& name, NzTexture* texture)
{
static const unsigned int maxUnits = NazaraRenderer->GetMaxTextureUnits();
unsigned int unitUsed = m_textures.size();
if (unitUsed >= maxUnits)
{
NazaraError("Unable to use texture \"" + name + "\" for shader: all available texture units are used");
return false;
}
// À partir d'ici nous savons qu'il y a au moins un identifiant de texture libre
GLint location = GetUniformLocation(name);
if (location == -1)
{
NazaraError("Parameter name \"" + name + "\" not found in shader");
return false;
}
nzUInt8 unit;
if (unitUsed == 0)
// Pas d'unité utilisée, la tâche est simple
unit = 0;
else
{
auto it = m_textures.rbegin(); // Itérateur vers la fin de la map
unit = it->second.unit;
if (unit == maxUnits-1)
{
// Il y a une place libre, mais pas à la fin
for (; it != m_textures.rend(); ++it)
{
if (unit - it->second.unit > 1) // Si l'espace entre les indices est supérieur à 1, alors il y a une place libre
{
unit--;
break;
}
}
}
else
// Il y a une place libre à la fin
unit++;
}
m_textures[location] = TextureSlot{unit, texture};
Lock();
glUniform1i(location, unit);
Unlock();
return true;
}
void NzGLSLShader::Unbind()
{
glUseProgram(0);
}
void NzGLSLShader::Unlock() const
void NzGLSLShader::Unlock()
{
if (m_lockedLevel == 0)
if (lockedLevel == 0)
{
NazaraWarning("Unlock called on non-locked texture");
return;
}
if (--m_lockedLevel == 0 && m_lockedPrevious != m_program)
glUseProgram(m_lockedPrevious);
if (--lockedLevel == 0 && lockedPrevious != m_program)
glUseProgram(lockedPrevious);
}

View File

@ -34,7 +34,7 @@ class NzGLSLShader : public NzShaderImpl
bool IsLoaded(nzShaderType type) const;
bool Load(nzShaderType type, const NzString& source);
bool Lock() const;
bool Lock();
bool SendBoolean(const NzString& name, bool value);
bool SendDouble(const NzString& name, double value);
@ -42,16 +42,23 @@ class NzGLSLShader : public NzShaderImpl
bool SendInteger(const NzString& name, int value);
bool SendMatrix(const NzString& name, const NzMatrix4d& matrix);
bool SendMatrix(const NzString& name, const NzMatrix4f& matrix);
bool SendTexture(const NzString& name, NzTexture* texture);
void Unbind();
void Unlock() const;
void Unlock();
private:
struct TextureSlot
{
nzUInt8 unit;
NzTexture* texture;
};
mutable std::map<NzString, GLint> m_idCache;
mutable GLuint m_lockedPrevious;
std::map<GLint, TextureSlot> m_textures;
GLuint m_program;
GLuint m_shaders[nzShaderType_Count];
mutable nzUInt8 m_lockedLevel;
nzUInt8 m_textureFreeID;
NzShader* m_parent;
NzString m_log;
};

View File

@ -37,7 +37,10 @@ m_id(0)
NzOcclusionQuery::~NzOcclusionQuery()
{
if (m_id)
glDeleteQueries(1, reinterpret_cast<GLuint*>(&m_id));
{
GLuint query = static_cast<GLuint>(m_id);
glDeleteQueries(1, &query);
}
}
void NzOcclusionQuery::Begin()

View File

@ -255,6 +255,8 @@ bool NzOpenGL::Initialize()
glGetShaderiv = reinterpret_cast<PFNGLGETSHADERIVPROC>(LoadEntry("glGetShaderiv"));
glGetShaderSource = reinterpret_cast<PFNGLGETSHADERSOURCEPROC>(LoadEntry("glGetShaderSource"));
glGetTexImage = reinterpret_cast<PFNGLGETTEXIMAGEPROC>(LoadEntry("glGetTexImage"));
glGetTexLevelParameterfv = reinterpret_cast<PFNGLGETTEXLEVELPARAMETERFVPROC>(LoadEntry("glGetTexLevelParameterfv"));
glGetTexLevelParameteriv = reinterpret_cast<PFNGLGETTEXLEVELPARAMETERIVPROC>(LoadEntry("glGetTexLevelParameteriv"));
glGetTexParameterfv = reinterpret_cast<PFNGLGETTEXPARAMETERFVPROC>(LoadEntry("glGetTexParameterfv"));
glGetTexParameteriv = reinterpret_cast<PFNGLGETTEXPARAMETERIVPROC>(LoadEntry("glGetTexParameteriv"));
glGetUniformLocation = reinterpret_cast<PFNGLGETUNIFORMLOCATIONPROC>(LoadEntry("glGetUniformLocation"));
@ -445,6 +447,9 @@ bool NzOpenGL::Initialize()
}
}
// TextureCompression_s3tc
openGLextensions[NzOpenGL::TextureCompression_s3tc] = IsSupported("GL_EXT_texture_compression_s3tc");
// VertexArrayObject
if (openGLversion >= 420 || IsSupported("GL_ARB_texture_storage"))
{
@ -587,6 +592,8 @@ PFNGLGETSHADERSOURCEPROC glGetShaderSource = nullptr;
PFNGLGETSTRINGPROC glGetString = nullptr;
PFNGLGETSTRINGIPROC glGetStringi = nullptr;
PFNGLGETTEXIMAGEPROC glGetTexImage = nullptr;
PFNGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv = nullptr;
PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv = nullptr;
PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv = nullptr;
PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv = nullptr;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;

View File

@ -8,6 +8,7 @@
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Context.hpp>
#include <Nazara/Renderer/ContextParameters.hpp>
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
namespace
@ -25,12 +26,28 @@ NzRenderWindow::NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32
m_context(nullptr)
{
Create(mode, title, style, parameters);
#ifdef NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Failed to create render window");
throw std::runtime_error("Constructor failed");
}
#endif
}
NzRenderWindow::NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters) :
m_context(nullptr)
{
Create(handle, parameters);
#ifdef NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Failed to create render window");
throw std::runtime_error("Constructor failed");
}
#endif
}
NzRenderWindow::~NzRenderWindow()

View File

@ -30,7 +30,8 @@ namespace
4 // nzElementUsage_TexCoord
};
const GLenum openglPrimitive[] = {
const GLenum openglPrimitive[] =
{
GL_LINES, // nzPrimitiveType_LineList,
GL_LINE_STRIP, // nzPrimitiveType_LineStrip,
GL_POINTS, // nzPrimitiveType_PointList,
@ -310,6 +311,12 @@ bool NzRenderer::SetShader(NzShader* shader)
if (shader == m_shader)
return true;
if (m_shader)
{
m_shader->m_impl->Unbind();
m_shader = nullptr;
}
if (shader)
{
#if NAZARA_RENDERER_SAFE
@ -328,11 +335,6 @@ bool NzRenderer::SetShader(NzShader* shader)
m_shader = shader;
}
else if (m_shader)
{
m_shader->m_impl->Unbind();
m_shader = nullptr;
}
return true;
}
@ -408,7 +410,7 @@ void NzRenderer::Uninitialize()
// Libération des VAOs
for (auto it = m_vaos.begin(); it != m_vaos.end(); ++it)
{
GLuint vao = it->second;
GLuint vao = static_cast<GLuint>(it->second);
glDeleteVertexArrays(1, &vao);
}

View File

@ -371,6 +371,19 @@ bool NzShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix)
return m_impl->SendMatrix(name, matrix);
}
bool NzShader::SendTexture(const NzString& name, NzTexture* texture)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
#endif
return m_impl->SendTexture(name, texture);
}
void NzShader::Unlock()
{
#if NAZARA_RENDERER_SAFE

View File

@ -10,6 +10,7 @@
#include <Nazara/Renderer/Shader.hpp>
class NzRenderer;
class NzTexture;
class NzVertexBuffer;
class NzVertexDeclaration;
@ -36,7 +37,7 @@ class NzShaderImpl
virtual bool Load(nzShaderType type, const NzString& source) = 0;
virtual bool Lock() const = 0;
virtual bool Lock() = 0;
virtual bool SendBoolean(const NzString& name, bool value) = 0;
virtual bool SendDouble(const NzString& name, double value) = 0;
@ -44,9 +45,10 @@ class NzShaderImpl
virtual bool SendInteger(const NzString& name, int value) = 0;
virtual bool SendMatrix(const NzString& name, const NzMatrix4d& matrix) = 0;
virtual bool SendMatrix(const NzString& name, const NzMatrix4f& matrix) = 0;
virtual bool SendTexture(const NzString& name, NzTexture* texture) = 0;
virtual void Unbind() = 0;
virtual void Unlock() const = 0;
virtual void Unlock() = 0;
};
#endif // NAZARA_SHADERIMPL_HPP

File diff suppressed because it is too large Load Diff

View File

@ -160,6 +160,9 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width,
{
ReleaseImage();
if (width == 0 || height == 0 || depth == 0)
return true;
#if NAZARA_UTILITY_SAFE
if (!NzPixelFormat::IsValid(format))
{
@ -191,6 +194,9 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width,
}
break;
case nzImageType_3D:
break;
case nzImageType_Cubemap:
if (depth > 1)
{
@ -206,13 +212,11 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width,
break;
default:
break;
NazaraInternalError("Image type not handled");
return false;
}
#endif
if (width == 0 || height == 0 || depth == 0)
return true;
levelCount = std::min(levelCount, GetMaxLevel(width, height, depth));
nzUInt8** levels = new nzUInt8*[levelCount];
@ -279,7 +283,7 @@ unsigned int NzImage::GetDepth(nzUInt8 level) const
}
#endif
return std::max(m_sharedImage->depth/(1 << level), 1U);
return std::max(m_sharedImage->depth >> level, 1U);
}
nzPixelFormat NzImage::GetFormat() const
@ -297,7 +301,7 @@ unsigned int NzImage::GetHeight(nzUInt8 level) const
}
#endif
return std::max(m_sharedImage->height/(1 << level), 1U);
return std::max(m_sharedImage->height >> level, 1U);
}
nzUInt8 NzImage::GetLevelCount() const
@ -446,9 +450,9 @@ unsigned int NzImage::GetSize(nzUInt8 level) const
}
#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)) *
return (std::max(m_sharedImage->width >> level, 1U)) *
(std::max(m_sharedImage->height >> level, 1U)) *
((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::max(m_sharedImage->depth >> level, 1U)) *
NzPixelFormat::GetBPP(m_sharedImage->format);
}
@ -467,7 +471,7 @@ unsigned int NzImage::GetWidth(nzUInt8 level) const
}
#endif
return std::max(m_sharedImage->width/(1 << level), 1U);
return std::max(m_sharedImage->width >> level, 1U);
}
bool NzImage::IsCompressed() const
@ -523,22 +527,23 @@ bool NzImage::SetLevelCount(nzUInt8 levelCount)
EnsureOwnership();
nzUInt8 oldLevelCount = m_sharedImage->levelCount;
nzUInt8 maxLevelCount = std::max(levelCount, oldLevelCount);
m_sharedImage->levelCount = levelCount; // Pour faire fonctionner GetSize
nzUInt8** pixels = new nzUInt8*[levelCount];
for (unsigned int i = 0; i < levelCount; ++i)
for (unsigned int i = 0; i < maxLevelCount; ++i)
{
if (i < m_sharedImage->levelCount)
if (i < oldLevelCount)
pixels[i] = m_sharedImage->pixels[i];
else if (i < levelCount)
pixels[i] = new nzUInt8[GetSize(i)];
else
{
unsigned int size = GetSize(i);
pixels[i] = new nzUInt8[size];
std::memcpy(pixels[i], m_sharedImage->pixels[i], size);
}
delete[] m_sharedImage->pixels[i];
}
delete[] m_sharedImage->pixels;
m_sharedImage->levelCount = levelCount;
m_sharedImage->pixels = pixels;
return true;
@ -702,23 +707,23 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z
return false;
}
if (level >= m_sharedImage->levelCount)
{
NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')');
return false;
}
if (rect.x+rect.width > (m_sharedImage->width << level) || rect.y+rect.height > (m_sharedImage->height) << level)
if (rect.x+rect.width > std::max(m_sharedImage->width >> level, 1U) || rect.y+rect.height > std::max(m_sharedImage->height >> level, 1U))
{
NazaraError("Rectangle dimensions are out of bounds");
return false;
}
if (z >= (m_sharedImage->depth << level))
if (z >= std::max(m_sharedImage->depth >> level, 1U))
{
NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')');
return false;
}
if (level >= m_sharedImage->levelCount)
{
NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')');
return false;
}
#endif
EnsureOwnership();
@ -749,7 +754,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 leve
if (m_sharedImage->type != nzImageType_Cubemap)
{
NazaraError("Update is designed for cubemaps, use Update instead");
NazaraError("UpdateFace is designed for cubemaps, use Update instead");
return false;
}
@ -785,7 +790,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect
if (m_sharedImage->type != nzImageType_Cubemap)
{
NazaraError("Update is designed for cubemaps, use Update instead");
NazaraError("UpdateFace is designed for cubemaps, use Update instead");
return false;
}
@ -801,15 +806,15 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect
return false;
}
if (level >= m_sharedImage->levelCount)
if (rect.x+rect.width > std::max(m_sharedImage->width >> level, 1U) || rect.y+rect.height > std::max(m_sharedImage->height >> level, 1U))
{
NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')');
NazaraError("Rectangle dimensions are out of bounds");
return false;
}
if (rect.x+rect.width > (m_sharedImage->width << level) || rect.y+rect.height > (m_sharedImage->height) << level)
if (level >= m_sharedImage->levelCount)
{
NazaraError("Rectangle dimensions are out of bounds");
NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')');
return false;
}
#endif
@ -861,7 +866,7 @@ nzUInt8 NzImage::GetMaxLevel(unsigned int width, unsigned int height, unsigned i
unsigned int heightLevel = std::log(height)/l2;
unsigned int depthLevel = std::log(depth)/l2;
return std::max(std::max(widthLevel, heightLevel), depthLevel);
return std::max(std::max(std::max(widthLevel, heightLevel), depthLevel), 1U);
}
void NzImage::RegisterFileLoader(const NzString& extensions, LoadFileFunction loadFile)

View File

@ -93,7 +93,7 @@ namespace
unsigned int width = header.xmax - header.xmin+1;
unsigned int height = header.ymax - header.ymin+1;
if (!resource->Create(nzImageType_2D, nzPixelFormat_RGB8, width, height))
if (!resource->Create(nzImageType_2D, nzPixelFormat_RGB8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1))
{
NazaraError("Failed to create image");
return false;

View File

@ -111,7 +111,7 @@ namespace
if (format == nzPixelFormat_Undefined)
format = formats[bpp-1];
if (!resource->Create(nzImageType_2D, format, width, height))
if (!resource->Create(nzImageType_2D, format, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1))
{
NazaraError("Failed to create image");
stbi_image_free(ptr);