From 83c40e66641661fa50ecf62dc893f96507796d90 Mon Sep 17 00:00:00 2001 From: nicebyte <12521759+nicebyte@users.noreply.github.com> Date: Mon, 7 Jan 2019 15:16:00 -0800 Subject: [PATCH] Make 4-channel versions of certain image operations. (#676) Background: with the Vulkan backend, RGB8 textures do not work (at least not on my hadrware). This makes me unable to run some examples, because they use normal maps in RGB8 format. It appears that the following commit addresses the problem by adding a special command line option to mipgen: https://github.com/google/filament/commit/8dda07bf2c19f9ebd8ab499ca2c3849d7b1f031f However, processing normal maps with this option does not work: certain assertions in the image library fail. This PR changes these functions in the image library to handle 4-channel images instead of failing. --- libs/image/src/ImageOps.cpp | 42 +++++++++++++++++++++------------ libs/image/src/ImageSampler.cpp | 17 ++++++++++--- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/libs/image/src/ImageOps.cpp b/libs/image/src/ImageOps.cpp index 7edb16ff59..36da604961 100644 --- a/libs/image/src/ImageOps.cpp +++ b/libs/image/src/ImageOps.cpp @@ -17,10 +17,12 @@ #include #include +#include #include #include #include +#include using namespace math; @@ -117,28 +119,38 @@ LinearImage verticalFlip(const LinearImage& image) { return result; } -LinearImage vectorsToColors(const LinearImage& image) { - ASSERT_PRECONDITION(image.getChannels() == 3, "Must be a 3-channel image."); +template , + class Offset = std::ratio<1, 1>> +LinearImage applyScaleOffset(const LinearImage& image) { const uint32_t width = image.getWidth(), height = image.getHeight(); - LinearImage result(width, height, 3); - auto src = (float3 const*) image.getPixelRef(); - auto dst = (float3*) result.getPixelRef(); + LinearImage result(width, height, image.getChannels()); + auto src = (VecT const*) image.getPixelRef(); + auto dst = (VecT*) result.getPixelRef(); + constexpr float scale_f = + static_cast(Scale::num) / static_cast(Scale::den); + constexpr float offset_f = + static_cast(Offset::num) / static_cast(Offset::den); for (uint32_t n = 0, end = width * height; n < end; ++n) { - dst[n] = 0.5f * (src[n] + float3(1)); + dst[n] = scale_f * src[n] + VecT(offset_f); } return result; } +LinearImage vectorsToColors(const LinearImage& image) { + ASSERT_PRECONDITION(image.getChannels() == 3 || image.getChannels() == 4, + "Must be a 3 or 4 channel image"); + return image.getChannels() == 3 + ? applyScaleOffset, std::ratio<1, 2>>(image) + : applyScaleOffset, std::ratio<1, 2>>(image); +} + LinearImage colorsToVectors(const LinearImage& image) { - ASSERT_PRECONDITION(image.getChannels() == 3, "Must be a 3-channel image."); - const uint32_t width = image.getWidth(), height = image.getHeight(); - LinearImage result(width, height, 3); - auto src = (float3 const*) image.getPixelRef(); - auto dst = (float3*) result.getPixelRef(); - for (uint32_t n = 0, end = width * height; n < end; ++n) { - dst[n] = 2.0f * src[n] - float3(1); - } - return result; + ASSERT_PRECONDITION(image.getChannels() == 3 || image.getChannels() == 4, + "Must be a 3 or 4 channel image"); + return image.getChannels() == 3 + ? applyScaleOffset, std::ratio<-1, 1>>(image) + : applyScaleOffset, std::ratio<-1, 1>>(image); } LinearImage extractChannel(const LinearImage& source, uint32_t channel) { diff --git a/libs/image/src/ImageSampler.cpp b/libs/image/src/ImageSampler.cpp index db6f0d1f63..aabd3bfcb1 100644 --- a/libs/image/src/ImageSampler.cpp +++ b/libs/image/src/ImageSampler.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -204,15 +205,25 @@ FilterFunction createFilterFunction(Filter ftype) { return fn; } -void normalize(LinearImage& image) { - ASSERT_PRECONDITION(image.getChannels() == 3, "Must be a 3-channel image."); +template +void normalizeImpl(LinearImage& image) { const uint32_t width = image.getWidth(), height = image.getHeight(); - auto vecs = (math::float3*) image.getPixelRef(); + auto vecs = (VecT*) image.getPixelRef(); for (uint32_t n = 0; n < width * height; ++n) { vecs[n] = normalize(vecs[n]); } } +void normalize(LinearImage& image) { + ASSERT_PRECONDITION(image.getChannels() == 3 || image.getChannels() == 4, + "Must be a 3 or 4 channel image"); + if (image.getChannels() == 3) { + normalizeImpl(image); + } else { + normalizeImpl(image); + } +} + LinearImage resampleImage1D(const LinearImage& source, MadProgram* program, uint32_t twidth, Filter filter, float left, float right, float filterRadiusMultiplier) { const uint32_t swidth = source.getWidth();