diff --git a/libraries/image/src/image/CubeMap.cpp b/libraries/image/src/image/CubeMap.cpp index 1e25ffb9c0..f511890c58 100644 --- a/libraries/image/src/image/CubeMap.cpp +++ b/libraries/image/src/image/CubeMap.cpp @@ -15,13 +15,14 @@ #include #include "RandomAndNoise.h" -#include "TextureProcessing.h" #include "ImageLogging.h" #ifndef M_PI #define M_PI 3.14159265359 #endif +#include + using namespace image; static const glm::vec3 FACE_NORMALS[24] = { @@ -321,7 +322,7 @@ CubeMap::CubeMap(int width, int height, int mipCount) { reset(width, height, mipCount); } -CubeMap::CubeMap(const std::vector& faces, gpu::Element srcTextureFormat, int mipCount, const std::atomic& abortProcessing) { +CubeMap::CubeMap(const std::vector& faces, int mipCount, const std::atomic& abortProcessing) { reset(faces.front().getWidth(), faces.front().getHeight(), mipCount); int face; @@ -330,13 +331,11 @@ CubeMap::CubeMap(const std::vector& faces, gpu::Element srcTextureFormat, surface.setAlphaMode(nvtt::AlphaMode_None); surface.setWrapMode(nvtt::WrapMode_Mirror); - std::vector floatPixels; - floatPixels.resize(_width * _height); - // Compute mips for (face = 0; face < 6; face++) { - convertToFloatFromPacked(faces[face].getBits(), _width, _height, faces[face].getBytesPerLineCount(), srcTextureFormat, floatPixels.data(), _width); - surface.setImage(nvtt::InputFormat_RGBA_32F, _width, _height, 1, &floatPixels.front().x); + Image faceImage = faces[face].getConvertedToFormat(Image::Format_RGBAF); + + surface.setImage(nvtt::InputFormat_RGBA_32F, _width, _height, 1, faceImage.editBits()); auto mipLevel = 0; copySurface(surface, editFace(0, face), getMipLineStride(0)); @@ -359,6 +358,18 @@ CubeMap::CubeMap(const std::vector& faces, gpu::Element srcTextureFormat, } } +void CubeMap::applyGamma(float value) { + for (auto& mip : _mips) { + for (auto& face : mip) { + for (auto& pixel : face) { + pixel.r = std::pow(pixel.r, value); + pixel.g = std::pow(pixel.g, value); + pixel.b = std::pow(pixel.b, value); + } + } + } +} + void CubeMap::copyFace(int width, int height, const glm::vec4* source, size_t srcLineStride, glm::vec4* dest, size_t dstLineStride) { for (int y = 0; y < height; y++) { std::copy(source, source + width, dest); diff --git a/libraries/image/src/image/CubeMap.h b/libraries/image/src/image/CubeMap.h index 100164d7df..0745267cb6 100644 --- a/libraries/image/src/image/CubeMap.h +++ b/libraries/image/src/image/CubeMap.h @@ -31,11 +31,13 @@ namespace image { public: CubeMap(int width, int height, int mipCount); - CubeMap(const std::vector& faces, gpu::Element faceFormat, int mipCount, const std::atomic& abortProcessing = false); + CubeMap(const std::vector& faces, int mipCount, const std::atomic& abortProcessing = false); void reset(int width, int height, int mipCount); void copyTo(CubeMap& other) const; + void applyGamma(float value); + gpu::uint16 getMipCount() const { return (gpu::uint16)_mips.size(); } int getMipWidth(gpu::uint16 mipLevel) const { return std::max(1, _width >> mipLevel); diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 0752783355..2ef83e42d8 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -75,8 +75,8 @@ Image Image::getScaled(glm::uvec2 dstSize, AspectRatioMode ratioMode, Transforma glm::vec4* floatPixels = new glm::vec4[getWidth()*getHeight()]; auto unpackFunc = getHDRUnpackingFunction(); auto floatDataIt = floatPixels; - for (auto lineNb = 0; lineNb < getHeight(); lineNb++) { - const glm::uint32* srcPixelIt = reinterpret_cast(getScanLine(lineNb)); + for (glm::uint32 lineNb = 0; lineNb < getHeight(); lineNb++) { + const glm::uint32* srcPixelIt = reinterpret_cast(getScanLine((int)lineNb)); const glm::uint32* srcPixelEnd = srcPixelIt + getWidth(); while (srcPixelIt < srcPixelEnd) { @@ -96,7 +96,7 @@ Image Image::getScaled(glm::uvec2 dstSize, AspectRatioMode ratioMode, Transforma if (transformMode == Qt::TransformationMode::FastTransformation) { filter = nvtt::ResizeFilter_Box; } - surface.resize(dstSize.x, dstSize.y, 1, nvtt::ResizeFilter_Box); + surface.resize(dstSize.x, dstSize.y, 1, filter); auto srcRedIt = reinterpret_cast(surface.channel(0)); auto srcGreenIt = reinterpret_cast(surface.channel(1)); @@ -124,8 +124,8 @@ Image Image::getScaled(glm::uvec2 dstSize, AspectRatioMode ratioMode, Transforma QImage resizedImage((int)dstSize.x, (int)dstSize.y, (QImage::Format)Image::Format_PACKED_FLOAT); auto packFunc = getHDRPackingFunction(); - for (auto lineNb = 0; lineNb < dstSize.y; lineNb++) { - glm::uint32* dstPixelIt = reinterpret_cast(resizedImage.scanLine(lineNb)); + for (glm::uint32 lineNb = 0; lineNb < dstSize.y; lineNb++) { + glm::uint32* dstPixelIt = reinterpret_cast(resizedImage.scanLine((int)lineNb)); glm::uint32* dstPixelEnd = dstPixelIt + dstSize.x; while (dstPixelIt < dstPixelEnd) { diff --git a/libraries/image/src/image/TextureProcessing.cpp b/libraries/image/src/image/TextureProcessing.cpp index 589335d816..d3b34b84fe 100644 --- a/libraries/image/src/image/TextureProcessing.cpp +++ b/libraries/image/src/image/TextureProcessing.cpp @@ -615,7 +615,7 @@ nvtt::OutputHandler* getNVTTCompressionOutputHandler(gpu::Texture* outputTexture } } -void convertToHDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic& abortProcessing, int face) { +void convertImageToHDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic& abortProcessing, int face) { assert(image.hasFloatFormat()); Image localCopy = image.getConvertedToFormat(Image::Format_RGBAF); @@ -658,21 +658,20 @@ void convertToHDRTexture(gpu::Texture* texture, Image&& image, BackendTarget tar } } -void convertToLDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic& abortProcessing, int face) { +void convertImageToLDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic& abortProcessing, int face) { // Take a local copy to force move construction // https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f18-for-consume-parameters-pass-by-x-and-stdmove-the-parameter Image localCopy = std::move(image); - assert(localCopy.getFormat() != Image::Format_PACKED_FLOAT); - if (localCopy.getFormat() != Image::Format_ARGB32) { - localCopy = localCopy.getConvertedToFormat(Image::Format_ARGB32); - } - const int width = localCopy.getWidth(), height = localCopy.getHeight(); auto mipFormat = texture->getStoredMipFormat(); int mipLevel = baseMipLevel; if (target != BackendTarget::GLES32) { + if (localCopy.getFormat() != Image::Format_ARGB32) { + localCopy = localCopy.getConvertedToFormat(Image::Format_ARGB32); + } + const void* data = static_cast(localCopy.getBits()); nvtt::TextureType textureType = nvtt::TextureType_2D; nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB; @@ -864,12 +863,12 @@ void convertImageToTexture(gpu::Texture* texture, Image& image, BackendTarget ta PROFILE_RANGE(resource_parse, "convertToTextureWithMips"); if (target == BackendTarget::GLES32) { - convertToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face); + convertImageToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face); } else { if (image.hasFloatFormat()) { - convertToHDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face); + convertImageToHDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face); } else { - convertToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face); + convertImageToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face); } } } @@ -1487,12 +1486,31 @@ Image convertToHDRFormat(Image&& srcImage, gpu::Element format) { return hdrImage; } -void convolveForGGX(const std::vector& faces, gpu::Element faceFormat, gpu::Texture* texture, BackendTarget target, const std::atomic& abortProcessing = false) { +static bool isLinearTextureFormat(gpu::Element format) { + return !((format == gpu::Element::COLOR_SRGBA_32) + || (format == gpu::Element::COLOR_SBGRA_32) + || (format == gpu::Element::COLOR_SR_8) + || (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGB) + || (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_MASK) + || (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA) + || (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_HIGH) + || (format == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB) + || (format == gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA) + || (format == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA)); +} + +void convolveForGGX(const std::vector& faces, gpu::Texture* texture, BackendTarget target, const std::atomic& abortProcessing = false) { PROFILE_RANGE(resource_parse, "convolveForGGX"); - CubeMap source(faces, faceFormat, texture->getNumMips(), abortProcessing); + CubeMap source(faces, texture->getNumMips(), abortProcessing); CubeMap output(texture->getWidth(), texture->getHeight(), texture->getNumMips()); + if (!faces.front().hasFloatFormat()) { + source.applyGamma(2.2f); + } source.convolveForGGX(output, abortProcessing); + if (!isLinearTextureFormat(texture->getTexelFormat())) { + output.applyGamma(1.0f/2.2f); + } for (int face = 0; face < 6; face++) { for (gpu::uint16 mipLevel = 0; mipLevel < output.getMipCount(); mipLevel++) { @@ -1601,7 +1619,7 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(Image&& srcIm if (options & CUBE_GGX_CONVOLVE) { // Performs and convolution AND mip map generation - convolveForGGX(faces, GPU_CUBEMAP_HDR_FORMAT, theTexture.get(), target, abortProcessing); + convolveForGGX(faces, theTexture.get(), target, abortProcessing); } else { // Create mip maps and compress to final format in one go for (uint8 face = 0; face < faces.size(); ++face) {