From 71cf7876c5e9c55957daedb31d69cca0229779c4 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 22 Jun 2012 23:18:37 +0200 Subject: [PATCH] Optimized image flipping Added new extensible flipping system Optimized NzTexture::Update(Face) --- include/Nazara/Utility/PixelFormat.hpp | 14 ++++ include/Nazara/Utility/PixelFormat.inl | 101 +++++++++++++++++++++++++ src/Nazara/Renderer/Texture.cpp | 33 ++++---- src/Nazara/Utility/Image.cpp | 23 +----- src/Nazara/Utility/PixelFormat.cpp | 4 + 5 files changed, 140 insertions(+), 35 deletions(-) diff --git a/include/Nazara/Utility/PixelFormat.hpp b/include/Nazara/Utility/PixelFormat.hpp index 755236779..a69ad0092 100644 --- a/include/Nazara/Utility/PixelFormat.hpp +++ b/include/Nazara/Utility/PixelFormat.hpp @@ -9,6 +9,7 @@ #include #include +#include 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 s_flipFunctions[nzPixelFlipping_Max+1]; }; #include diff --git a/include/Nazara/Utility/PixelFormat.inl b/include/Nazara/Utility/PixelFormat.inl index fa5a7da9d..917450700 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/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(src), reinterpret_cast(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(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(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(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(src); + nzUInt8* dstPtr = reinterpret_cast(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) diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index eae6087c4..44706f6c5 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -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; } diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 11284bd52..1f7211514 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -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; diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 999aba443..c4178b4b4 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -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::s_flipFunctions[nzPixelFlipping_Max+1];