Optimized image flipping
Added new extensible flipping system Optimized NzTexture::Update(Face)
This commit is contained in:
parent
acc9b99ad2
commit
71cf7876c5
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <map>
|
||||
|
||||
enum nzPixelFormat
|
||||
{
|
||||
|
|
@ -49,6 +50,14 @@ enum nzPixelFormat
|
|||
nzPixelFormat_Max = nzPixelFormat_RGBA8
|
||||
};
|
||||
|
||||
enum nzPixelFlipping
|
||||
{
|
||||
nzPixelFlipping_Horizontally,
|
||||
nzPixelFlipping_Vertically,
|
||||
|
||||
nzPixelFlipping_Max = nzPixelFlipping_Vertically
|
||||
};
|
||||
|
||||
class NzUtility;
|
||||
|
||||
class NzPixelFormat
|
||||
|
|
@ -57,10 +66,13 @@ class NzPixelFormat
|
|||
|
||||
public:
|
||||
typedef nzUInt8* (*ConvertFunction)(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst);
|
||||
typedef void (*FlipFunction)(unsigned int width, unsigned int height, unsigned int depth, const nzUInt8* src, nzUInt8* dst);
|
||||
|
||||
static bool Convert(nzPixelFormat srcFormat, nzPixelFormat dstFormat, const void* src, void* dst);
|
||||
static bool Convert(nzPixelFormat srcFormat, nzPixelFormat dstFormat, const void* start, const void* end, void* dst);
|
||||
|
||||
static bool Flip(nzPixelFlipping flipping, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst);
|
||||
|
||||
static nzUInt8 GetBPP(nzPixelFormat format);
|
||||
|
||||
static bool HasAlpha(nzPixelFormat format);
|
||||
|
|
@ -70,6 +82,7 @@ class NzPixelFormat
|
|||
static bool IsValid(nzPixelFormat format);
|
||||
|
||||
static void SetConvertFunction(nzPixelFormat srcFormat, nzPixelFormat dstFormat, ConvertFunction func);
|
||||
static void SetFlipFunction(nzPixelFlipping flipping, nzPixelFormat format, FlipFunction func);
|
||||
|
||||
static NzString ToString(nzPixelFormat format);
|
||||
|
||||
|
|
@ -78,6 +91,7 @@ class NzPixelFormat
|
|||
static void Uninitialize();
|
||||
|
||||
static NAZARA_API ConvertFunction s_convertFunctions[nzPixelFormat_Max+1][nzPixelFormat_Max+1];
|
||||
static NAZARA_API std::map<nzPixelFormat, FlipFunction> s_flipFunctions[nzPixelFlipping_Max+1];
|
||||
};
|
||||
|
||||
#include <Nazara/Utility/PixelFormat.inl>
|
||||
|
|
|
|||
|
|
@ -68,6 +68,102 @@ inline bool NzPixelFormat::Convert(nzPixelFormat srcFormat, nzPixelFormat dstFor
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool NzPixelFormat::Flip(nzPixelFlipping flipping, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!IsValid(format))
|
||||
{
|
||||
NazaraError("Invalid pixel format");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto it = s_flipFunctions[flipping].find(format);
|
||||
if (it != s_flipFunctions[flipping].end())
|
||||
it->second(width, height, depth, reinterpret_cast<const nzUInt8*>(src), reinterpret_cast<nzUInt8*>(dst));
|
||||
else
|
||||
{
|
||||
// Flipping générique
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (IsCompressed(format))
|
||||
{
|
||||
NazaraError("No function to flip compressed format");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
nzUInt8 bpp = GetBPP(format);
|
||||
unsigned int lineStride = width*bpp;
|
||||
switch (flipping)
|
||||
{
|
||||
case nzPixelFlipping_Horizontally:
|
||||
{
|
||||
if (src == dst)
|
||||
{
|
||||
for (unsigned int z = 0; z < depth; ++z)
|
||||
{
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(dst) + width*height*z;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
for (unsigned int x = 0; x < width/2; ++x)
|
||||
std::swap_ranges(&ptr[x*bpp], &ptr[(x+1)*bpp], &ptr[(width-x)*bpp]);
|
||||
|
||||
ptr += lineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int z = 0; z < depth; ++z)
|
||||
{
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(dst) + width*height*z;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
for (unsigned int x = 0; x < width; ++x)
|
||||
std::memcpy(&ptr[x*bpp], &ptr[(width-x)*bpp], bpp);
|
||||
|
||||
ptr += lineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case nzPixelFlipping_Vertically:
|
||||
{
|
||||
if (src == dst)
|
||||
{
|
||||
for (unsigned int z = 0; z < depth; ++z)
|
||||
{
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(dst) + width*height*z;
|
||||
for (unsigned int y = 0; y < height/2; ++y)
|
||||
std::swap_ranges(&ptr[y*lineStride], &ptr[(y+1)*lineStride-1], &ptr[(height-y-1)*lineStride]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int z = 0; z < depth; ++z)
|
||||
{
|
||||
const nzUInt8* srcPtr = reinterpret_cast<const nzUInt8*>(src);
|
||||
nzUInt8* dstPtr = reinterpret_cast<nzUInt8*>(dst) + (width-1)*height*depth*bpp;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
std::memcpy(dstPtr, srcPtr, lineStride);
|
||||
|
||||
srcPtr += lineStride;
|
||||
dstPtr -= lineStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format)
|
||||
{
|
||||
switch (format)
|
||||
|
|
@ -198,6 +294,11 @@ inline void NzPixelFormat::SetConvertFunction(nzPixelFormat srcFormat, nzPixelFo
|
|||
s_convertFunctions[srcFormat][dstFormat] = func;
|
||||
}
|
||||
|
||||
inline void NzPixelFormat::SetFlipFunction(nzPixelFlipping flipping, nzPixelFormat format, FlipFunction func)
|
||||
{
|
||||
s_flipFunctions[flipping][format] = func;
|
||||
}
|
||||
|
||||
inline NzString NzPixelFormat::ToString(nzPixelFormat format)
|
||||
{
|
||||
switch (format)
|
||||
|
|
|
|||
|
|
@ -1353,12 +1353,13 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve
|
|||
nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format);
|
||||
|
||||
// Inversion de la texture pour le repère d'OpenGL
|
||||
NzImage mirrored;
|
||||
mirrored.Create(m_impl->type, m_impl->format, cube.width, cube.height, cube.depth);
|
||||
mirrored.Update(pixels);
|
||||
|
||||
if (!mirrored.FlipVertically())
|
||||
unsigned int size = cube.width*cube.height*cube.depth*bpp;
|
||||
nzUInt8* mirrored = new nzUInt8[size];
|
||||
if (!NzPixelFormat::Flip(nzPixelFlipping_Vertically, m_impl->format, cube.width, cube.height, cube.depth, pixels, mirrored))
|
||||
{
|
||||
NazaraWarning("Failed to flip image");
|
||||
std::memcpy(mirrored, pixels, size);
|
||||
}
|
||||
|
||||
SetUnpackAlignement(bpp);
|
||||
|
||||
|
|
@ -1366,15 +1367,15 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve
|
|||
switch (m_impl->type)
|
||||
{
|
||||
case nzImageType_1D:
|
||||
glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format.dataFormat, format.dataType, mirrored.GetConstPixels());
|
||||
glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format.dataFormat, format.dataType, mirrored);
|
||||
break;
|
||||
|
||||
case nzImageType_2D:
|
||||
glTexSubImage2D(GL_TEXTURE_2D, level, cube.x, height-cube.height-cube.y, cube.width, cube.height, format.dataFormat, format.dataType, mirrored.GetConstPixels());
|
||||
glTexSubImage2D(GL_TEXTURE_2D, level, cube.x, height-cube.height-cube.y, cube.width, cube.height, format.dataFormat, format.dataType, mirrored);
|
||||
break;
|
||||
|
||||
case nzImageType_3D:
|
||||
glTexSubImage3D(GL_TEXTURE_3D, level, cube.x, height-cube.height-cube.y, cube.z, cube.width, cube.height, cube.depth, format.dataFormat, format.dataType, mirrored.GetConstPixels());
|
||||
glTexSubImage3D(GL_TEXTURE_3D, level, cube.x, height-cube.height-cube.y, cube.z, cube.width, cube.height, cube.depth, format.dataFormat, format.dataType, mirrored);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1382,6 +1383,8 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve
|
|||
}
|
||||
UnlockTexture(m_impl);
|
||||
|
||||
delete[] mirrored;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1502,19 +1505,21 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe
|
|||
nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format);
|
||||
|
||||
// Inversion de la texture pour le repère d'OpenGL
|
||||
NzImage mirrored;
|
||||
mirrored.Create(m_impl->type, m_impl->format, rect.width, rect.height);
|
||||
mirrored.Update(pixels);
|
||||
|
||||
if (!mirrored.FlipVertically())
|
||||
unsigned int size = rect.width*rect.height*bpp;
|
||||
nzUInt8* mirrored = new nzUInt8[size];
|
||||
if (!NzPixelFormat::Flip(nzPixelFlipping_Vertically, m_impl->format, rect.width, rect.height, 1, pixels, mirrored))
|
||||
{
|
||||
NazaraWarning("Failed to flip image");
|
||||
std::memcpy(mirrored, pixels, size);
|
||||
}
|
||||
|
||||
SetUnpackAlignement(bpp);
|
||||
|
||||
LockTexture(m_impl);
|
||||
glTexSubImage2D(cubemapFace[face], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored.GetConstPixels());
|
||||
glTexSubImage2D(cubemapFace[face], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored);
|
||||
UnlockTexture(m_impl);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -494,24 +494,12 @@ bool NzImage::FlipHorizontally()
|
|||
|
||||
EnsureOwnership();
|
||||
|
||||
nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format);
|
||||
unsigned int width = m_sharedImage->width;
|
||||
unsigned int height = m_sharedImage->height;
|
||||
unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth;
|
||||
for (unsigned int level = 0; level < m_sharedImage->levelCount; ++level)
|
||||
{
|
||||
for (unsigned int z = 0; z < depth; ++z)
|
||||
{
|
||||
nzUInt8* ptr = &m_sharedImage->pixels[level][width*height*z];
|
||||
unsigned int lineStride = width*bpp;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
for (unsigned int x = 0; x < width/2; ++x)
|
||||
std::swap_ranges(&ptr[x*bpp], &ptr[(x+1)*bpp], &ptr[(width-x)*bpp]);
|
||||
|
||||
ptr += lineStride;
|
||||
}
|
||||
}
|
||||
NzPixelFormat::Flip(nzPixelFlipping_Horizontally, m_sharedImage->format, width, height, depth, m_sharedImage->pixels[level], m_sharedImage->pixels[level]);
|
||||
|
||||
if (width > 1U)
|
||||
width >>= 1;
|
||||
|
|
@ -545,19 +533,12 @@ bool NzImage::FlipVertically()
|
|||
|
||||
EnsureOwnership();
|
||||
|
||||
nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format);
|
||||
unsigned int width = m_sharedImage->width;
|
||||
unsigned int height = m_sharedImage->height;
|
||||
unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth;
|
||||
for (unsigned int level = 0; level < m_sharedImage->levelCount; ++level)
|
||||
{
|
||||
for (unsigned int z = 0; z < depth; ++z)
|
||||
{
|
||||
nzUInt8* ptr = &m_sharedImage->pixels[level][width*height*z];
|
||||
unsigned int lineStride = width*bpp;
|
||||
for (unsigned int y = 0; y < height/2; ++y)
|
||||
std::swap_ranges(&ptr[y*lineStride], &ptr[(y+1)*lineStride-1], &ptr[(height-y-1)*lineStride]);
|
||||
}
|
||||
NzPixelFormat::Flip(nzPixelFlipping_Vertically, m_sharedImage->format, width, height, depth, m_sharedImage->pixels[level], m_sharedImage->pixels[level]);
|
||||
|
||||
if (width > 1U)
|
||||
width >>= 1;
|
||||
|
|
|
|||
|
|
@ -1315,6 +1315,10 @@ bool NzPixelFormat::Initialize()
|
|||
void NzPixelFormat::Uninitialize()
|
||||
{
|
||||
std::memset(s_convertFunctions, 0, (nzPixelFormat_Max+1)*(nzPixelFormat_Max+1)*sizeof(NzPixelFormat::ConvertFunction));
|
||||
|
||||
for (unsigned int i = 0; i <= nzPixelFlipping_Max; ++i)
|
||||
s_flipFunctions[i].clear();
|
||||
}
|
||||
|
||||
NzPixelFormat::ConvertFunction NzPixelFormat::s_convertFunctions[nzPixelFormat_Max+1][nzPixelFormat_Max+1] = {{0}}; ///FIXME: Fonctionne correctement ?
|
||||
std::map<nzPixelFormat, NzPixelFormat::FlipFunction> NzPixelFormat::s_flipFunctions[nzPixelFlipping_Max+1];
|
||||
|
|
|
|||
Loading…
Reference in New Issue