Merge branch 'master' of https://github.com/google/filament
This commit is contained in:
@@ -214,8 +214,7 @@ std::unique_ptr<uint8_t[]> fromLinearTosRGB(const LinearImage& image) {
|
||||
T* d = reinterpret_cast<T*>(dst.get());
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x, d += 3) {
|
||||
float3 const* src = reinterpret_cast<float3 const*>(
|
||||
image.getPixelRef((uint32_t) x, (uint32_t) y));
|
||||
auto src = image.get<float3>((uint32_t) x, (uint32_t) y);
|
||||
float3 l(linearTosRGB(saturate(*src)) * std::numeric_limits<T>::max());
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
d[i] = T(l[i]);
|
||||
@@ -238,8 +237,7 @@ std::unique_ptr<uint8_t[]> fromLinearToRGB(const LinearImage& image) {
|
||||
T* d = reinterpret_cast<T*>(dst.get());
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x, d += 3) {
|
||||
float3 const* src = reinterpret_cast<float3 const*>(
|
||||
image.getPixelRef((uint32_t) x, (uint32_t) y));
|
||||
auto src = image.get<float3>((uint32_t) x, (uint32_t) y);
|
||||
float3 l(saturate(*src) * std::numeric_limits<T>::max());
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
d[i] = T(l[i]);
|
||||
@@ -262,8 +260,7 @@ std::unique_ptr<uint8_t[]> fromLinearToRGBM(const LinearImage& image) {
|
||||
T* d = reinterpret_cast<T*>(dst.get());
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x, d += 4) {
|
||||
float3 const* src = reinterpret_cast<float3 const*>(
|
||||
image.getPixelRef((uint32_t) x, (uint32_t) y));
|
||||
auto src = image.get<float3>((uint32_t) x, (uint32_t) y);
|
||||
float4 l(linearToRGBM(*src) * std::numeric_limits<T>::max());
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
d[i] = T(l[i]);
|
||||
@@ -273,6 +270,25 @@ std::unique_ptr<uint8_t[]> fromLinearToRGBM(const LinearImage& image) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Creates a packed single-channel integer-based image from a floating-point image.
|
||||
// For example if T is uint8_t, then this performs a transformation from [0,1] to [0,255].
|
||||
template <typename T>
|
||||
std::unique_ptr<uint8_t[]> fromLinearToGrayscale(const LinearImage& image) {
|
||||
const size_t w = image.getWidth();
|
||||
const size_t h = image.getHeight();
|
||||
assert(image.getChannels() == 1);
|
||||
std::unique_ptr<uint8_t[]> dst(new uint8_t[w * h * sizeof(T)]);
|
||||
T* d = reinterpret_cast<T*>(dst.get());
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
float const* p = image.getPixelRef(0, y);
|
||||
for (size_t x = 0; x < w; ++x, ++p, ++d) {
|
||||
const float gray = math::saturate(*p) * std::numeric_limits<T>::max();
|
||||
d[0] = T(gray);
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Constructs a 3-channel LinearImage from an untyped data blob.
|
||||
// The "proc" lambda converts a single color component into a float.
|
||||
// The "transform" lambda performs an arbitrary float-to-float transformation.
|
||||
@@ -280,7 +296,7 @@ template<typename T, typename PROCESS, typename TRANSFORM>
|
||||
static LinearImage toLinear(size_t w, size_t h, size_t bpr,
|
||||
const uint8_t* src, PROCESS proc, TRANSFORM transform) {
|
||||
LinearImage result((uint32_t) w, (uint32_t) h, 3);
|
||||
math::float3* d = reinterpret_cast<math::float3*>(result.getPixelRef());
|
||||
auto d = result.get<math::float3>();
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
T const* p = reinterpret_cast<T const*>(src + y * bpr);
|
||||
for (size_t x = 0; x < w; ++x, p += 3) {
|
||||
@@ -308,7 +324,7 @@ template<typename T, typename PROCESS, typename TRANSFORM>
|
||||
static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr,
|
||||
const uint8_t* src, PROCESS proc, TRANSFORM transform) {
|
||||
LinearImage result((uint32_t) w, (uint32_t) h, 4);
|
||||
math::float4* d = reinterpret_cast<math::float4*>(result.getPixelRef());
|
||||
auto d = result.get<math::float4>();
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
T const* p = reinterpret_cast<T const*>(src + y * bpr);
|
||||
for (size_t x = 0; x < w; ++x, p += 4) {
|
||||
@@ -332,7 +348,7 @@ static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr,
|
||||
// Constructs a 3-channel LinearImage from RGBM data.
|
||||
inline LinearImage toLinearFromRGBM(math::float4 const* src, uint32_t w, uint32_t h) {
|
||||
LinearImage result(w, h, 3);
|
||||
math::float3* dst = reinterpret_cast<math::float3*>(result.getPixelRef());
|
||||
auto dst = result.get<math::float3>();
|
||||
for (uint32_t row = 0; row < h; ++row) {
|
||||
for (uint32_t col = 0; col < w; ++col, ++src, ++dst) {
|
||||
*dst = RGBMtoLinear(*src);
|
||||
|
||||
@@ -38,6 +38,9 @@ LinearImage verticalFlip(const LinearImage& image);
|
||||
// Transforms normals (components live in [-1,+1]) into colors (components live in [0,+1]).
|
||||
LinearImage vectorsToColors(const LinearImage& image);
|
||||
|
||||
// Creates a single-channel image by extracting the selected channel.
|
||||
LinearImage extractChannel(const LinearImage& image, uint32_t channel);
|
||||
|
||||
// Constructs a multi-channel image by copying data from a sequence of single-channel images.
|
||||
LinearImage combineChannels(std::initializer_list<LinearImage> images);
|
||||
LinearImage combineChannels(LinearImage const* img, size_t count);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef IMAGE_LINEARIMAGE_H
|
||||
#define IMAGE_LINEARIMAGE_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
@@ -64,11 +65,13 @@ public:
|
||||
* Gets a pointer to the underlying pixel data.
|
||||
*/
|
||||
float* getPixelRef() { return mData; }
|
||||
template<typename T> T* get() { return reinterpret_cast<T*>(mData); }
|
||||
|
||||
/**
|
||||
* Gets a pointer to immutable pixel data.
|
||||
*/
|
||||
float const* getPixelRef() const { return mData; }
|
||||
template<typename T> T const* get() const { return reinterpret_cast<T const*>(mData); }
|
||||
|
||||
/**
|
||||
* Gets a pointer to the pixel data at the given column and row. (not bounds checked)
|
||||
@@ -77,6 +80,11 @@ public:
|
||||
return mData + (column + row * mWidth) * mChannels;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* get(uint32_t column, uint32_t row) {
|
||||
return reinterpret_cast<T*>(getPixelRef(column, row));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pointer to the immutable pixel data at the given column and row. (not bounds checked)
|
||||
*/
|
||||
@@ -84,10 +92,16 @@ public:
|
||||
return mData + (column + row * mWidth) * mChannels;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T const* get(uint32_t column, uint32_t row) const {
|
||||
return reinterpret_cast<T const*>(getPixelRef(column, row));
|
||||
}
|
||||
|
||||
uint32_t getWidth() const { return mWidth; }
|
||||
uint32_t getHeight() const { return mHeight; }
|
||||
uint32_t getChannels() const { return mChannels; }
|
||||
void reset() { *this = LinearImage(); }
|
||||
bool isValid() const { return mData; }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -128,6 +128,19 @@ LinearImage vectorsToColors(const LinearImage& image) {
|
||||
return result;
|
||||
}
|
||||
|
||||
LinearImage extractChannel(const LinearImage& source, uint32_t channel) {
|
||||
const uint32_t width = source.getWidth(), height = source.getHeight();
|
||||
const uint32_t nchan = source.getChannels();
|
||||
ASSERT_PRECONDITION(channel < nchan, "Channel is out of range.");
|
||||
LinearImage result(width, height, 1);
|
||||
auto src = source.getPixelRef();
|
||||
auto dst = result.getPixelRef();
|
||||
for (uint32_t n = 0, npixels = width * height; n < npixels; ++n, ++dst, src += nchan) {
|
||||
dst[0] = src[channel];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LinearImage combineChannels(std::initializer_list<LinearImage> images) {
|
||||
size_t count = images.end() - images.begin();
|
||||
return combineChannels(images.begin(), count);
|
||||
|
||||
@@ -247,7 +247,7 @@ TEST_F(ImageTest, ColorTransformRGB) { // NOLINT
|
||||
LinearImage img = image::toLinear<uint16_t>(w, h, bpr, data,
|
||||
[ ](uint16_t v) -> uint16_t { return v; },
|
||||
sRGBToLinear<math::float3>);
|
||||
auto pixels = reinterpret_cast<float3*>(img.getPixelRef());
|
||||
auto pixels = img.get<float3>();
|
||||
ASSERT_NEAR(pixels[0].x, 0.0f, 0.001f);
|
||||
ASSERT_NEAR(pixels[0].y, 0.0f, 0.001f);
|
||||
ASSERT_NEAR(pixels[0].z, 0.0f, 0.001f);
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
#ifndef IMAGE_IMAGEDECODER_H_
|
||||
#define IMAGE_IMAGEDECODER_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <image/Image.h>
|
||||
#include <image/LinearImage.h>
|
||||
|
||||
namespace image {
|
||||
|
||||
@@ -30,12 +31,12 @@ public:
|
||||
SRGB
|
||||
};
|
||||
|
||||
static Image decode(std::istream& stream, const std::string& sourceName,
|
||||
static LinearImage decode(std::istream& stream, const std::string& sourceName,
|
||||
ColorSpace sourceSpace = ColorSpace::SRGB);
|
||||
|
||||
class Decoder {
|
||||
public:
|
||||
virtual Image decode() = 0;
|
||||
virtual LinearImage decode() = 0;
|
||||
virtual ~Decoder() = default;
|
||||
|
||||
ColorSpace getColorSpace() const noexcept {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <image/Image.h>
|
||||
#include <image/LinearImage.h>
|
||||
|
||||
namespace image {
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
};
|
||||
|
||||
// the encode function only expects images that store pixels as floats
|
||||
static void encode(std::ostream& stream, Format format, const Image& image,
|
||||
static void encode(std::ostream& stream, Format format, const LinearImage& image,
|
||||
const std::string& compression, const std::string& destName);
|
||||
|
||||
static Format chooseFormat(const std::string& name, bool forceLinear = false);
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
class Encoder {
|
||||
public:
|
||||
virtual void encode(const Image& image) = 0;
|
||||
virtual void encode(const LinearImage& image) = 0;
|
||||
virtual ~Encoder() = default;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <image/ColorTransform.h>
|
||||
#include <image/ImageOps.h>
|
||||
|
||||
namespace image {
|
||||
|
||||
@@ -60,7 +61,7 @@ private:
|
||||
void init();
|
||||
|
||||
// ImageDecoder::Decoder interface
|
||||
virtual Image decode() override;
|
||||
virtual LinearImage decode() override;
|
||||
|
||||
static void cb_error(png_structp, png_const_charp);
|
||||
static void cb_stream(png_structp png, png_bytep buffer, png_size_t size);
|
||||
@@ -89,7 +90,7 @@ private:
|
||||
HDRDecoder& operator=(const HDRDecoder&) = delete;
|
||||
|
||||
// ImageDecoder::Decoder interface
|
||||
virtual Image decode() override;
|
||||
virtual LinearImage decode() override;
|
||||
|
||||
static const char sigRadiance[];
|
||||
static const char sigRGBE[];
|
||||
@@ -112,7 +113,7 @@ private:
|
||||
PSDDecoder& operator = (const PSDDecoder&) = delete;
|
||||
|
||||
// ImageDecoder::Decoder interface
|
||||
virtual Image decode() override;
|
||||
virtual LinearImage decode() override;
|
||||
|
||||
static const char sig[];
|
||||
std::istream& mStream;
|
||||
@@ -134,7 +135,7 @@ private:
|
||||
EXRDecoder& operator = (const EXRDecoder&) = delete;
|
||||
|
||||
// ImageDecoder::Decoder interface
|
||||
virtual Image decode() override;
|
||||
virtual LinearImage decode() override;
|
||||
|
||||
static const char sig[];
|
||||
std::istream& mStream;
|
||||
@@ -144,7 +145,7 @@ private:
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
Image ImageDecoder::decode(std::istream& stream, const std::string& sourceName,
|
||||
LinearImage ImageDecoder::decode(std::istream& stream, const std::string& sourceName,
|
||||
ColorSpace sourceSpace) {
|
||||
|
||||
Format format = Format::NONE;
|
||||
@@ -168,7 +169,7 @@ Image ImageDecoder::decode(std::istream& stream, const std::string& sourceName,
|
||||
std::unique_ptr<Decoder> decoder;
|
||||
switch (format) {
|
||||
case Format::NONE:
|
||||
return Image();
|
||||
return LinearImage();
|
||||
case Format::PNG:
|
||||
decoder.reset(PNGDecoder::create(stream));
|
||||
decoder->setColorSpace(sourceSpace);
|
||||
@@ -265,7 +266,7 @@ static Image toLinearWithAlphaDeprecated(size_t w, size_t h, size_t bpr,
|
||||
return Image(std::move(dst), w, h, w * sizeof(math::float4), sizeof(math::float4), 4);
|
||||
}
|
||||
|
||||
Image PNGDecoder::decode() {
|
||||
LinearImage PNGDecoder::decode() {
|
||||
std::unique_ptr<uint8_t[]> imageData;
|
||||
try {
|
||||
mInfo = png_create_info_struct(mPNG);
|
||||
@@ -304,22 +305,22 @@ Image PNGDecoder::decode() {
|
||||
|
||||
if (colorType == PNG_COLOR_TYPE_RGBA) {
|
||||
if (getColorSpace() == ImageDecoder::ColorSpace::SRGB) {
|
||||
return toLinearWithAlphaDeprecated<uint16_t>(width, height, rowBytes, imageData,
|
||||
return toLinearWithAlpha<uint16_t>(width, height, rowBytes, imageData,
|
||||
[ ](uint16_t v) -> uint16_t { return ntohs(v); },
|
||||
sRGBToLinear<math::float4>);
|
||||
} else {
|
||||
return toLinearWithAlphaDeprecated<uint16_t>(width, height, rowBytes, imageData,
|
||||
return toLinearWithAlpha<uint16_t>(width, height, rowBytes, imageData,
|
||||
[ ](uint16_t v) -> uint16_t { return ntohs(v); },
|
||||
[ ](const math::float4& color) -> math::float4 { return color; });
|
||||
}
|
||||
} else {
|
||||
// Convert to linear float (PNG 16 stores data in network order (big endian).
|
||||
if (getColorSpace() == ImageDecoder::ColorSpace::SRGB) {
|
||||
return toLinearDeprecated<uint16_t>(width, height, rowBytes, imageData,
|
||||
return toLinear<uint16_t>(width, height, rowBytes, imageData,
|
||||
[ ](uint16_t v) -> uint16_t { return ntohs(v); },
|
||||
sRGBToLinear<math::float3>);
|
||||
} else {
|
||||
return toLinearDeprecated<uint16_t>(width, height, rowBytes, imageData,
|
||||
return toLinear<uint16_t>(width, height, rowBytes, imageData,
|
||||
[ ](uint16_t v) -> uint16_t { return ntohs(v); },
|
||||
[ ](const math::float3& color) -> math::float3 { return color; });
|
||||
}
|
||||
@@ -330,7 +331,7 @@ Image PNGDecoder::decode() {
|
||||
mStream.seekg(mStreamStartPos);
|
||||
imageData.release();
|
||||
}
|
||||
return Image();
|
||||
return LinearImage();
|
||||
}
|
||||
|
||||
void PNGDecoder::cb_stream(png_structp png, png_bytep buffer, png_size_t size) {
|
||||
@@ -375,7 +376,7 @@ HDRDecoder::HDRDecoder(std::istream& stream)
|
||||
|
||||
HDRDecoder::~HDRDecoder() = default;
|
||||
|
||||
Image HDRDecoder::decode() {
|
||||
LinearImage HDRDecoder::decode() {
|
||||
try {
|
||||
float gamma;
|
||||
float exposure;
|
||||
@@ -398,13 +399,11 @@ Image HDRDecoder::decode() {
|
||||
} while (true);
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> data(new uint8_t[width * height * sizeof(math::float3)]);
|
||||
Image image(std::move(data), width, height, width*sizeof(math::float3), sizeof(math::float3));
|
||||
LinearImage image(width, height, 3);
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (sx == '-') flags |= Image::FLIP_X;
|
||||
if (sy == '+') flags |= Image::FLIP_Y;
|
||||
image.flip(flags);
|
||||
if (sx == '-') image = horizontalFlip(image);
|
||||
if (sy == '+') image = verticalFlip(image);
|
||||
|
||||
uint16_t w;
|
||||
uint16_t magic;
|
||||
@@ -447,7 +446,7 @@ Image HDRDecoder::decode() {
|
||||
uint8_t const* g = &rgbe[width];
|
||||
uint8_t const* b = &rgbe[2*width];
|
||||
uint8_t const* e = &rgbe[3*width];
|
||||
math::float3* i = static_cast<math::float3*>(image.getPixelRef(0, y));
|
||||
math::float3* i = reinterpret_cast<math::float3*>(image.getPixelRef(0, y));
|
||||
// (rgb/256) * 2^(e-128)
|
||||
for (size_t x=0 ; x<width ; x++, r++, g++, b++, e++) {
|
||||
math::float3 v(r[0], g[0], b[0]);
|
||||
@@ -461,7 +460,7 @@ Image HDRDecoder::decode() {
|
||||
std::cerr << "Runtime error while decoding HDR: " << e.what() << std::endl;
|
||||
mStream.seekg(mStreamStartPos);
|
||||
}
|
||||
return Image();
|
||||
return LinearImage();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@@ -483,7 +482,7 @@ PSDDecoder::PSDDecoder(std::istream& stream)
|
||||
|
||||
PSDDecoder::~PSDDecoder() = default;
|
||||
|
||||
Image PSDDecoder::decode() {
|
||||
LinearImage PSDDecoder::decode() {
|
||||
#pragma pack(push, 1)
|
||||
// IMPORTANT NOTE: PSD files use big endian storage
|
||||
struct Header {
|
||||
@@ -542,15 +541,13 @@ Image PSDDecoder::decode() {
|
||||
throw std::runtime_error("compressed images are not supported");
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> data(new uint8_t[width * height * sizeof(math::float3)]);
|
||||
Image image(std::move(data), width, height,
|
||||
width * sizeof(math::float3), sizeof(math::float3));
|
||||
LinearImage image(width, height, 3);
|
||||
|
||||
if (depth == 32) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
math::float3& pixel = *static_cast<math::float3*>(image.getPixelRef(x, y));
|
||||
math::float3& pixel = *reinterpret_cast<math::float3*>(image.getPixelRef(x, y));
|
||||
pixel[i] = read32(mStream);
|
||||
}
|
||||
}
|
||||
@@ -559,7 +556,7 @@ Image PSDDecoder::decode() {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
math::float3& pixel = *static_cast<math::float3*>(image.getPixelRef(x, y));
|
||||
math::float3& pixel = *reinterpret_cast<math::float3*>(image.getPixelRef(x, y));
|
||||
pixel[i] = read16(mStream);
|
||||
}
|
||||
}
|
||||
@@ -573,7 +570,7 @@ Image PSDDecoder::decode() {
|
||||
mStream.seekg(mStreamStartPos);
|
||||
}
|
||||
|
||||
return Image();
|
||||
return LinearImage();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@@ -595,7 +592,7 @@ EXRDecoder::EXRDecoder(std::istream& stream, const std::string& sourceName)
|
||||
|
||||
EXRDecoder::~EXRDecoder() = default;
|
||||
|
||||
Image EXRDecoder::decode() {
|
||||
LinearImage EXRDecoder::decode() {
|
||||
try {
|
||||
// copy the EXR data in memory
|
||||
std::vector<unsigned char> src;
|
||||
@@ -614,19 +611,17 @@ Image EXRDecoder::decode() {
|
||||
if (ret != TINYEXR_SUCCESS) {
|
||||
std::cerr << "Could not decode OpenEXR: " << error << std::endl;
|
||||
mStream.seekg(mStreamStartPos);
|
||||
return Image();
|
||||
return LinearImage();
|
||||
}
|
||||
|
||||
src.resize(0);
|
||||
|
||||
std::unique_ptr<uint8_t[]> data(new uint8_t[width * height * sizeof(math::float3)]);
|
||||
Image image(std::move(data), static_cast<size_t>(width), static_cast<size_t>(height),
|
||||
width * sizeof(math::float3), sizeof(math::float3));
|
||||
LinearImage image(width, height, 3);
|
||||
|
||||
size_t i = 0;
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
math::float3& pixel = *static_cast<math::float3*>(image.getPixelRef(x, y));
|
||||
math::float3& pixel = *reinterpret_cast<math::float3*>(image.getPixelRef(x, y));
|
||||
pixel.r = rgba[i++];
|
||||
pixel.g = rgba[i++];
|
||||
pixel.b = rgba[i++];
|
||||
@@ -642,7 +637,7 @@ Image EXRDecoder::decode() {
|
||||
mStream.seekg(mStreamStartPos);
|
||||
}
|
||||
|
||||
return Image();
|
||||
return LinearImage();
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
namespace image {
|
||||
|
||||
// TODO: (1) Remove usage of the old Image class. (2) Remove special treatment of 1-channel data.
|
||||
// TODO: Remove special treatment of 1-channel data.
|
||||
void updateOrCompare(LinearImage limgResult, const utils::Path& fnameGolden,
|
||||
ComparisonMode mode, float epsilon) {
|
||||
if (mode == ComparisonMode::SKIP) {
|
||||
@@ -36,26 +36,15 @@ void updateOrCompare(LinearImage limgResult, const utils::Path& fnameGolden,
|
||||
// Regenerate the PNG file at the given path.
|
||||
if (mode == ComparisonMode::UPDATE) {
|
||||
std::ofstream out(fnameGolden, std::ios::binary | std::ios::trunc);
|
||||
const size_t width = limgResult.getWidth();
|
||||
const size_t height = limgResult.getHeight();
|
||||
const size_t nchan = limgResult.getChannels();
|
||||
const size_t bpp = nchan * sizeof(float), bpr = width * bpp, nbytes = bpr * height;
|
||||
std::unique_ptr<uint8_t[]> data(new uint8_t[nbytes]);
|
||||
|
||||
auto format = ImageEncoder::Format::PNG_LINEAR;
|
||||
if (fnameGolden.getExtension() == "rgbm" && nchan == 3) {
|
||||
if (fnameGolden.getExtension() == "rgbm") {
|
||||
format = ImageEncoder::Format::RGBM;
|
||||
}
|
||||
|
||||
if (nchan != 1) {
|
||||
memcpy(data.get(), limgResult.getPixelRef(), nbytes);
|
||||
Image im(std::move(data), width, height, bpr, bpp, nchan);
|
||||
ImageEncoder::encode(out, format, im, "", fnameGolden);
|
||||
if (limgResult.getChannels() != 1) {
|
||||
ImageEncoder::encode(out, format, limgResult, "", fnameGolden);
|
||||
} else {
|
||||
auto limg2 = combineChannels({limgResult, limgResult, limgResult});
|
||||
memcpy(data.get(), limg2.getPixelRef(), nbytes);
|
||||
Image im(std::move(data), width, height, bpr, bpp, nchan);
|
||||
ImageEncoder::encode(out, format, im, "", fnameGolden);
|
||||
ImageEncoder::encode(out, format, limg2, "", fnameGolden);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -63,20 +52,13 @@ void updateOrCompare(LinearImage limgResult, const utils::Path& fnameGolden,
|
||||
// Load the PNG file at the given path.
|
||||
std::ifstream in(fnameGolden, std::ios::binary);
|
||||
ASSERT_PRECONDITION(in, "Unable to open: %s", fnameGolden.c_str());
|
||||
Image imgGolden = ImageDecoder::decode(in, fnameGolden, ImageDecoder::ColorSpace::LINEAR);
|
||||
const size_t width = imgGolden.getWidth(), height = imgGolden.getHeight();
|
||||
const size_t nchan = imgGolden.getChannelsCount();
|
||||
LinearImage limgGolden = ImageDecoder::decode(in, fnameGolden, ImageDecoder::ColorSpace::LINEAR);
|
||||
|
||||
// Convert 4-channel RGBM into proper RGB.
|
||||
LinearImage limgGolden;
|
||||
if (fnameGolden.getExtension() == "rgbm" && nchan == 4) {
|
||||
if (fnameGolden.getExtension() == "rgbm" && limgGolden.getChannels() == 4) {
|
||||
limgGolden = toLinearFromRGBM(
|
||||
static_cast<math::float4 const*>(imgGolden.getData()),
|
||||
imgGolden.getWidth(), imgGolden.getHeight());
|
||||
} else {
|
||||
limgGolden = LinearImage(width, height, nchan);
|
||||
memcpy(limgGolden.getPixelRef(), imgGolden.getData(),
|
||||
width * height * sizeof(float) * nchan);
|
||||
reinterpret_cast<math::float4 const*>(limgGolden.getPixelRef()),
|
||||
limgGolden.getWidth(), limgGolden.getHeight());
|
||||
}
|
||||
|
||||
// Expand the result image from L to RGB.
|
||||
|
||||
@@ -65,9 +65,9 @@ private:
|
||||
void init();
|
||||
|
||||
// ImageEncoder::Encoder interface
|
||||
virtual void encode(const Image& image) override;
|
||||
virtual void encode(const LinearImage& image) override;
|
||||
|
||||
int chooseColorType(const Image& image) const;
|
||||
int chooseColorType(const LinearImage& image) const;
|
||||
uint32_t getChannelsCount() const;
|
||||
|
||||
static void cb_error(png_structp png, png_const_charp error);
|
||||
@@ -98,7 +98,7 @@ private:
|
||||
HDREncoder& operator = (const HDREncoder&) = delete;
|
||||
|
||||
// ImageEncoder::Encoder interface
|
||||
virtual void encode(const Image& image) override;
|
||||
virtual void encode(const LinearImage& image) override;
|
||||
|
||||
static void float2rgbe(uint8_t rgbe[4], const math::float3& color);
|
||||
static size_t countRepeats(uint8_t const* data, size_t length);
|
||||
@@ -123,7 +123,7 @@ private:
|
||||
PSDEncoder& operator = (const PSDEncoder&) = delete;
|
||||
|
||||
// ImageEncoder::Encoder interface
|
||||
virtual void encode(const Image& image) override;
|
||||
virtual void encode(const LinearImage& image) override;
|
||||
|
||||
std::ostream& mStream;
|
||||
std::streampos mStreamStartPos;
|
||||
@@ -147,7 +147,7 @@ private:
|
||||
EXREncoder& operator = (const EXREncoder&) = delete;
|
||||
|
||||
// ImageEncoder::Encoder interface
|
||||
virtual void encode(const Image& image) override;
|
||||
virtual void encode(const LinearImage& image) override;
|
||||
|
||||
std::ostream& mStream;
|
||||
std::streampos mStreamStartPos;
|
||||
@@ -175,7 +175,7 @@ private:
|
||||
DDSEncoder& operator = (const DDSEncoder&) = delete;
|
||||
|
||||
// ImageEncoder::Encoder interface
|
||||
virtual void encode(const Image& image) override;
|
||||
virtual void encode(const LinearImage& image) override;
|
||||
|
||||
std::ostream& mStream;
|
||||
std::streampos mStreamStartPos;
|
||||
@@ -185,7 +185,7 @@ private:
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void ImageEncoder::encode(std::ostream& stream, Format format, const Image& image,
|
||||
void ImageEncoder::encode(std::ostream& stream, Format format, const LinearImage& image,
|
||||
const std::string& compression, const std::string& destName) {
|
||||
std::unique_ptr<Encoder> encoder;
|
||||
switch(format) {
|
||||
@@ -283,13 +283,14 @@ void PNGEncoder::init() {
|
||||
png_set_write_fn(mPNG, this, cb_stream, NULL);
|
||||
}
|
||||
|
||||
int PNGEncoder::chooseColorType(const Image& image) const {
|
||||
size_t channels = image.getChannelsCount();
|
||||
int PNGEncoder::chooseColorType(const LinearImage& image) const {
|
||||
size_t channels = image.getChannels();
|
||||
switch (channels) {
|
||||
case 1:
|
||||
return PNG_COLOR_TYPE_GRAY;
|
||||
case 3:
|
||||
default:
|
||||
std::cerr << "Warning: strange number of channels in PNG" << std::endl;
|
||||
case 3:
|
||||
switch (mFormat) {
|
||||
case PixelFormat::RGBM:
|
||||
return PNG_COLOR_TYPE_RGBA;
|
||||
@@ -308,10 +309,11 @@ uint32_t PNGEncoder::getChannelsCount() const {
|
||||
}
|
||||
}
|
||||
|
||||
void PNGEncoder::encode(const Image& image) {
|
||||
size_t srcChannels = image.getChannelsCount();
|
||||
void PNGEncoder::encode(const LinearImage& image) {
|
||||
size_t srcChannels = image.getChannels();
|
||||
if ((mFormat == PixelFormat::RGBM && srcChannels != 3) ||
|
||||
(srcChannels != 1 && srcChannels != 3)) {
|
||||
std::cerr << "Cannot encode PNG: " << srcChannels << " channels." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -333,22 +335,28 @@ void PNGEncoder::encode(const Image& image) {
|
||||
|
||||
png_write_info(mPNG, mInfo);
|
||||
|
||||
uint32_t channels = (srcChannels == 1 ? 1 : getChannelsCount());
|
||||
|
||||
std::unique_ptr<png_bytep[]> row_pointers(new png_bytep[height]);
|
||||
std::unique_ptr<uint8_t[]> data;
|
||||
switch (mFormat) {
|
||||
case PixelFormat::RGBM:
|
||||
data = fromLinearToRGBM<uint8_t>(image);
|
||||
break;
|
||||
case PixelFormat::sRGB:
|
||||
case PixelFormat::LINEAR_RGB:
|
||||
data = fromLinearToRGB<uint8_t>(image);
|
||||
break;
|
||||
|
||||
uint32_t dstChannels;
|
||||
if (srcChannels == 1) {
|
||||
dstChannels = 1;
|
||||
data = fromLinearToGrayscale<uint8_t>(image);
|
||||
} else {
|
||||
dstChannels = getChannelsCount();
|
||||
switch (mFormat) {
|
||||
case PixelFormat::RGBM:
|
||||
data = fromLinearToRGBM<uint8_t>(image);
|
||||
break;
|
||||
case PixelFormat::sRGB:
|
||||
case PixelFormat::LINEAR_RGB:
|
||||
data = fromLinearToRGB<uint8_t>(image);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
row_pointers[y] = reinterpret_cast<png_bytep>(&data[y * width * channels *
|
||||
row_pointers[y] = reinterpret_cast<png_bytep>(&data[y * width * dstChannels *
|
||||
sizeof(uint8_t)]);
|
||||
}
|
||||
|
||||
@@ -465,8 +473,8 @@ void HDREncoder::rle(std::ostream& out, uint8_t const* data, size_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
void HDREncoder::encode(const Image& image) {
|
||||
if (image.getChannelsCount() != 3) {
|
||||
void HDREncoder::encode(const LinearImage& image) {
|
||||
if (image.getChannels() != 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -495,7 +503,7 @@ void HDREncoder::encode(const Image& image) {
|
||||
for (size_t y=0 ; y<height ; y++) {
|
||||
// convert one scanline to RGBE
|
||||
uint8_t p[4];
|
||||
float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x=0 ; x<width ; ++x, ++data) {
|
||||
float2rgbe(p, *data);
|
||||
r[x] = p[0];
|
||||
@@ -559,13 +567,13 @@ static inline void write8i(std::ostream& stream, uint8_t v) {
|
||||
stream.write(reinterpret_cast<const char*>(&v), sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void PSDEncoder::encode(const Image& image) {
|
||||
void PSDEncoder::encode(const LinearImage& image) {
|
||||
static const uint16_t kColorModeRGB = 3;
|
||||
static const uint16_t kCompressionRAW = 0;
|
||||
// preview mode: 0 = highlight compression, 1 = exposure & gamma
|
||||
static const uint32_t kToningPreviewExposureGamma = 1;
|
||||
|
||||
if (image.getChannelsCount() != 3) {
|
||||
if (image.getChannels() != 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -652,7 +660,7 @@ void PSDEncoder::encode(const Image& image) {
|
||||
if (depth == 32) {
|
||||
for (size_t channel = 0; channel < 3; channel++) {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
write32(mStream, (*data)[channel]);
|
||||
data++;
|
||||
@@ -662,7 +670,7 @@ void PSDEncoder::encode(const Image& image) {
|
||||
} else {
|
||||
for (size_t channel = 0; channel < 3; channel++) {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
write16(mStream, linearTosRGB((*data)[channel]));
|
||||
data++;
|
||||
@@ -713,8 +721,8 @@ static int toEXRCompression(const std::string& c) {
|
||||
throw std::runtime_error("unknown compression scheme " + c);
|
||||
}
|
||||
|
||||
void EXREncoder::encode(const Image& image) {
|
||||
if (image.getChannelsCount() != 3) {
|
||||
void EXREncoder::encode(const LinearImage& image) {
|
||||
if (image.getChannels() != 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -738,7 +746,7 @@ void EXREncoder::encode(const Image& image) {
|
||||
|
||||
size_t i = 0;
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++, data++) {
|
||||
r[i] = data->r;
|
||||
g[i] = data->g;
|
||||
@@ -875,7 +883,7 @@ DDSEncoder::DDSEncoder(std::ostream& stream, const std::string& compression, Pix
|
||||
DDSEncoder::~DDSEncoder() {
|
||||
}
|
||||
|
||||
static uint32_t chooseBpp(const Image& image, const std::string& compression) {
|
||||
static uint32_t chooseBpp(const LinearImage& image, const std::string& compression) {
|
||||
size_t depth = 16;
|
||||
if (compression == "8") depth = 8;
|
||||
if (compression == "32") depth = 32;
|
||||
@@ -888,10 +896,10 @@ static uint32_t chooseBpp(const Image& image, const std::string& compression) {
|
||||
{ 4, 8, 16 },
|
||||
};
|
||||
|
||||
return formats[image.getChannelsCount() - 1][index];
|
||||
return formats[image.getChannels() - 1][index];
|
||||
}
|
||||
|
||||
static uint32_t chooseDXGIFormat(const Image& image, const std::string& compression) {
|
||||
static uint32_t chooseDXGIFormat(const LinearImage& image, const std::string& compression) {
|
||||
size_t depth = 16;
|
||||
if (compression == "8") depth = 8;
|
||||
if (compression == "32") depth = 32;
|
||||
@@ -904,10 +912,10 @@ static uint32_t chooseDXGIFormat(const Image& image, const std::string& compress
|
||||
{ DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT },
|
||||
};
|
||||
|
||||
return formats[image.getChannelsCount() - 1][index];
|
||||
return formats[image.getChannels() - 1][index];
|
||||
}
|
||||
|
||||
void DDSEncoder::encode(const Image& image) {
|
||||
void DDSEncoder::encode(const LinearImage& image) {
|
||||
try {
|
||||
size_t width = image.getWidth();
|
||||
size_t height = image.getHeight();
|
||||
@@ -946,7 +954,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
switch (mFormat) {
|
||||
case PixelFormat::sRGB:
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float* data = static_cast<float*>(image.getPixelRef(0, y));
|
||||
const float* data = image.getPixelRef(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
uint8_t b = (uint8_t) (linearTosRGB(saturate(*data)) * 255);
|
||||
mStream.write((const char*) &b, 1);
|
||||
@@ -956,7 +964,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
break;
|
||||
case PixelFormat::LINEAR_RGB:
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float* data = static_cast<float*>(image.getPixelRef(0, y));
|
||||
const float* data = image.getPixelRef(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
uint8_t b = (uint8_t) (saturate(*data) * 255);
|
||||
mStream.write((const char*) &b, 1);
|
||||
@@ -969,7 +977,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
}
|
||||
case DXGI_FORMAT_R16_FLOAT: {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float* data = static_cast<float*>(image.getPixelRef(0, y));
|
||||
const float* data = image.getPixelRef(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
math::half p = math::half(*data);
|
||||
mStream.write((const char*) &p, 2);
|
||||
@@ -980,7 +988,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
}
|
||||
case DXGI_FORMAT_R32_FLOAT: {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float* data = static_cast<float*>(image.getPixelRef(0, y));
|
||||
const float* data = image.getPixelRef(0, y);
|
||||
mStream.write((const char*) data, width * sizeof(float));
|
||||
}
|
||||
break;
|
||||
@@ -989,7 +997,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
switch (mFormat) {
|
||||
case PixelFormat::sRGB:
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float2* data = static_cast<float2*>(image.getPixelRef(0, y));
|
||||
const float2* data = reinterpret_cast<float2 const*>(image.getPixelRef(0, y));
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
uint8_t b;
|
||||
b = (uint8_t) (linearTosRGB(saturate(data->g)) * 255);
|
||||
@@ -1002,7 +1010,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
break;
|
||||
case PixelFormat::LINEAR_RGB:
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float2* data = static_cast<float2*>(image.getPixelRef(0, y));
|
||||
const float2* data = reinterpret_cast<float2 const*>(image.getPixelRef(0, y));
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
uint8_t b;
|
||||
b = (uint8_t) (saturate(data->g) * 255);
|
||||
@@ -1018,7 +1026,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
}
|
||||
case DXGI_FORMAT_R16G16_FLOAT: {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float2* data = static_cast<float2*>(image.getPixelRef(0, y));
|
||||
const float2* data = reinterpret_cast<float2 const*>(image.getPixelRef(0, y));
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
half2 p = half2(*data);
|
||||
mStream.write((const char*) &p, sizeof(p));
|
||||
@@ -1029,7 +1037,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
}
|
||||
case DXGI_FORMAT_R32G32_FLOAT: {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float2* data = static_cast<float2*>(image.getPixelRef(0, y));
|
||||
const float2* data = reinterpret_cast<float2 const*>(image.getPixelRef(0, y));
|
||||
mStream.write((const char*) data, width * sizeof(float2));
|
||||
}
|
||||
break;
|
||||
@@ -1038,7 +1046,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
switch (mFormat) {
|
||||
case PixelFormat::sRGB:
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
uint8_t r = (uint8_t) (linearTosRGB(saturate(data->r)) * 255);
|
||||
uint8_t g = (uint8_t) (linearTosRGB(saturate(data->g)) * 255);
|
||||
@@ -1052,7 +1060,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
break;
|
||||
case PixelFormat::LINEAR_RGB:
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
uint8_t r = (uint8_t) (saturate(data->r) * 255);
|
||||
uint8_t g = (uint8_t) (saturate(data->g) * 255);
|
||||
@@ -1068,7 +1076,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
}
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT: {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
half4 p = half4(half3(*data), 1);
|
||||
mStream.write((const char*) &p, sizeof(ushort4));
|
||||
@@ -1079,7 +1087,7 @@ void DDSEncoder::encode(const Image& image) {
|
||||
}
|
||||
case DXGI_FORMAT_R32G32B32A32_FLOAT: {
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
const float3* data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++) {
|
||||
float4 p = float4(3.0f, 3.0f, 3.0f, 1.0f);
|
||||
mStream.write((const char*) &p, sizeof(float4));
|
||||
|
||||
@@ -336,9 +336,8 @@ static void setup(Engine* engine, View* view, Scene* scene) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Image toLinear(size_t w, size_t h, size_t bpr, const uint8_t* src) {
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[w * h * 3 * sizeof(float3)]);
|
||||
Image result(std::move(buffer), w, h, w * sizeof(float3), sizeof(float3));
|
||||
static LinearImage toLinear(size_t w, size_t h, size_t bpr, const uint8_t* src) {
|
||||
LinearImage result(w, h, 3);
|
||||
math::float3* d = reinterpret_cast<math::float3*>(result.getPixelRef(0, 0));
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
T const* p = reinterpret_cast<T const*>(src + y * bpr);
|
||||
@@ -382,7 +381,7 @@ static void postRender(Engine*, View* view, Scene*, Renderer* renderer) {
|
||||
CaptureState* state = static_cast<CaptureState*>(user);
|
||||
const Viewport& v = state->view->getViewport();
|
||||
|
||||
Image image(toLinear<uint8_t>(v.width, v.height, v.width * 3,
|
||||
LinearImage image(toLinear<uint8_t>(v.width, v.height, v.width * 3,
|
||||
static_cast<uint8_t*>(buffer)));
|
||||
|
||||
int digits = (int) log10 ((double) g_materialVariantCount) + 1;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <math/scalar.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <image/Image.h>
|
||||
#include <imageio/ImageDecoder.h>
|
||||
#include <imageio/ImageEncoder.h>
|
||||
|
||||
@@ -90,6 +91,8 @@ static void extractCubemapFaces(const utils::Path& iname, const Cubemap& cm, con
|
||||
static void outputSh(std::ostream& out, const std::unique_ptr<math::double3[]>& sh, size_t numBands);
|
||||
static void outputSpectrum(std::ostream& out, const std::unique_ptr<math::double3[]>& sh,
|
||||
size_t numBands);
|
||||
static void saveImage(const std::string& path, ImageEncoder::Format format, const Image& image,
|
||||
const std::string& compression);
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -393,22 +396,27 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << "Decoding image..." << std::endl;
|
||||
}
|
||||
std::ifstream input_stream(iname.getPath(), std::ios::binary);
|
||||
Image inputImage = ImageDecoder::decode(input_stream, iname.getPath());
|
||||
if (!inputImage.isValid()) {
|
||||
std::cerr << "Unsupported image format!" << std::endl;
|
||||
exit(0);
|
||||
LinearImage linputImage = ImageDecoder::decode(input_stream, iname.getPath());
|
||||
if (!linputImage.isValid()) {
|
||||
std::cerr << "Unable to open image: " << iname.getPath() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if (inputImage.getChannelsCount() != 3) {
|
||||
if (linputImage.getChannels() != 3) {
|
||||
std::cerr << "Input image must be RGB (3 channels)! This image has "
|
||||
<< inputImage.getChannelsCount() << " channels." << std::endl;
|
||||
exit(0);
|
||||
<< linputImage.getChannels() << " channels." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Convert from LinearImage to the deprecated Image object which is used throughout cmgen.
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[
|
||||
linputImage.getWidth() * linputImage.getHeight() * sizeof(float3)]);
|
||||
const size_t width = linputImage.getWidth(), height = linputImage.getHeight();
|
||||
const size_t bpp = sizeof(float) * 3, bpr = bpp * width;
|
||||
memcpy(buf.get(), linputImage.getPixelRef(), height * bpr);
|
||||
Image inputImage(std::move(buf), width, height, bpr, bpp);
|
||||
|
||||
CubemapUtils::clamp(inputImage);
|
||||
|
||||
size_t width = inputImage.getWidth();
|
||||
size_t height = inputImage.getHeight();
|
||||
|
||||
if ((isPOT(width) && (width * 3 == height * 4)) ||
|
||||
(isPOT(height) && (height * 3 == width * 4))) {
|
||||
// This is cross cubemap
|
||||
@@ -588,10 +596,8 @@ void sphericalHarmonics(const utils::Path& iname, const Cubemap& inputCubemap) {
|
||||
}
|
||||
|
||||
if (g_sh_file == ShFile::SH_CROSS) {
|
||||
std::ofstream outputStream(g_sh_filename, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream,
|
||||
ImageEncoder::chooseFormat(g_sh_filename.getName()),
|
||||
image, g_compression, g_sh_filename);
|
||||
saveImage(g_sh_filename, ImageEncoder::chooseFormat(g_sh_filename.getName()),
|
||||
image, g_compression);
|
||||
}
|
||||
if (g_sh_file == ShFile::SH_TEXT) {
|
||||
std::ofstream outputStream(g_sh_filename, std::ios::trunc);
|
||||
@@ -609,9 +615,7 @@ void sphericalHarmonics(const utils::Path& iname, const Cubemap& inputCubemap) {
|
||||
std::string basename = iname.getNameWithoutExtension();
|
||||
utils::Path filePath =
|
||||
outputDir + (basename + "_sh" + (g_sh_irradiance ? "_i" : "_r") + ".png");
|
||||
std::ofstream outputStream(filePath, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, ImageEncoder::Format::PNG, image, "",
|
||||
filePath.getPath());
|
||||
saveImage(filePath, ImageEncoder::Format::PNG, image, "");
|
||||
}
|
||||
|
||||
{ // save a file with the "other one" (irradiance or radiance)
|
||||
@@ -620,9 +624,7 @@ void sphericalHarmonics(const utils::Path& iname, const Cubemap& inputCubemap) {
|
||||
std::string basename = iname.getNameWithoutExtension();
|
||||
utils::Path filePath =
|
||||
outputDir + (basename + "_sh" + (!g_sh_irradiance ? "_i" : "_r") + ".png");
|
||||
std::ofstream outputStream(filePath, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, ImageEncoder::Format::PNG, image, "",
|
||||
filePath.getPath());
|
||||
saveImage(filePath, ImageEncoder::Format::PNG, image, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -677,10 +679,7 @@ void iblMipmapPrefilter(const utils::Path& iname,
|
||||
std::string ext = ImageEncoder::chooseExtension(debug_format);
|
||||
std::string basename = iname.getNameWithoutExtension();
|
||||
utils::Path filePath = outputDir + (basename + "_is_m" + (std::to_string(level) + ext));
|
||||
|
||||
std::ofstream outputStream(filePath, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, debug_format, img,
|
||||
g_compression, filePath.getPath());
|
||||
saveImage(filePath, debug_format, img, g_compression);
|
||||
}
|
||||
|
||||
std::string ext = ImageEncoder::chooseExtension(g_format);
|
||||
@@ -688,9 +687,7 @@ void iblMipmapPrefilter(const utils::Path& iname,
|
||||
Cubemap::Face face = (Cubemap::Face)i;
|
||||
std::string filename = outputDir
|
||||
+ ("is_m" + std::to_string(level) + "_" + CubemapUtils::getFaceName(face) + ext);
|
||||
std::ofstream outputStream(filename, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, g_format, dst.getImageForFace(face),
|
||||
g_compression, filename);
|
||||
saveImage(filename, g_format, dst.getImageForFace(face), g_compression);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -737,10 +734,7 @@ void iblRoughnessPrefilter(const utils::Path& iname,
|
||||
std::string ext = ImageEncoder::chooseExtension(debug_format);
|
||||
std::string basename = iname.getNameWithoutExtension();
|
||||
utils::Path filePath = outputDir + (basename + "_roughness_m" + (std::to_string(level) + ext));
|
||||
|
||||
std::ofstream outputStream(filePath, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, debug_format, image,
|
||||
g_compression, filePath.getPath());
|
||||
saveImage(filePath, debug_format, image, g_compression);
|
||||
}
|
||||
|
||||
std::string ext = ImageEncoder::chooseExtension(g_format);
|
||||
@@ -748,9 +742,7 @@ void iblRoughnessPrefilter(const utils::Path& iname,
|
||||
Cubemap::Face face = (Cubemap::Face) j;
|
||||
std::string filename = outputDir
|
||||
+ ("m" + std::to_string(level) + "_" + CubemapUtils::getFaceName(face) + ext);
|
||||
std::ofstream outputStream(filename, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, g_format, dst.getImageForFace(face),
|
||||
g_compression, filename);
|
||||
saveImage(filename, g_format, dst.getImageForFace(face), g_compression);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -804,9 +796,8 @@ void iblLutDfg(const utils::Path& filename, size_t size, bool multiscatter) {
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} else {
|
||||
std::ofstream outputStream(filename, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::Format format = ImageEncoder::chooseFormat(filename.getName(), true);
|
||||
ImageEncoder::encode(outputStream, format, image, g_compression, filename.getPath());
|
||||
saveImage(filename, format, image, g_compression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,8 +810,23 @@ void extractCubemapFaces(const utils::Path& iname, const Cubemap& cm, const util
|
||||
for (size_t i=0 ; i<6 ; i++) {
|
||||
Cubemap::Face face = (Cubemap::Face)i;
|
||||
std::string filename(outputDir + (CubemapUtils::getFaceName(face) + ext));
|
||||
std::ofstream outputStream(filename, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(outputStream, g_format, cm.getImageForFace(face),
|
||||
g_compression, filename);
|
||||
saveImage(filename, g_format, cm.getImageForFace(face), g_compression);
|
||||
}
|
||||
}
|
||||
|
||||
static void saveImage(const std::string& path, ImageEncoder::Format format, const Image& image,
|
||||
const std::string& compression) {
|
||||
std::ofstream outputStream(path, std::ios::binary | std::ios::trunc);
|
||||
LinearImage linearImage(image.getWidth(), image.getHeight(), 3);
|
||||
|
||||
// Copy row by row since the image has padding.
|
||||
assert(image.getBytesPerPixel() == 12);
|
||||
const size_t w = image.getWidth(), h = image.getHeight();
|
||||
for (size_t row = 0; row < h; ++row) {
|
||||
float* dst = linearImage.getPixelRef(0, row);
|
||||
float const* src = static_cast<float const*>(image.getPixelRef(0, row));
|
||||
memcpy(dst, src, w * 12);
|
||||
}
|
||||
|
||||
ImageEncoder::encode(outputStream, format, linearImage, compression, path);
|
||||
}
|
||||
|
||||
@@ -100,12 +100,12 @@ static void processEnvMap(string inputPath, string resultPath, string goldenPath
|
||||
std::cout << "Reading result image from " << resultPath << std::endl;
|
||||
checkFileExistence(resultPath);
|
||||
std::ifstream resultStream(resultPath.c_str(), std::ios::binary);
|
||||
Image resultImage = ImageDecoder::decode(resultStream, resultPath);
|
||||
LinearImage resultImage = ImageDecoder::decode(resultStream, resultPath);
|
||||
ASSERT_EQ(resultImage.isValid(), true);
|
||||
ASSERT_EQ(resultImage.getChannelsCount(), 4);
|
||||
ASSERT_EQ(resultImage.getChannels(), 4);
|
||||
LinearImage resultLImage = toLinearFromRGBM(
|
||||
static_cast<math::float4 const*>(resultImage.getData()),
|
||||
(uint32_t) resultImage.getWidth(), (uint32_t) resultImage.getHeight());
|
||||
reinterpret_cast<math::float4 const*>(resultImage.getPixelRef()),
|
||||
resultImage.getWidth(), resultImage.getHeight());
|
||||
|
||||
std::cout << "Golden image is at " << goldenPath << std::endl;
|
||||
updateOrCompare(resultLImage, goldenPath, g_comparisonMode, 0.01f);
|
||||
|
||||
@@ -34,7 +34,7 @@ static image::ImageEncoder::Format g_format = image::ImageEncoder::Format::PNG;
|
||||
static bool g_formatSpecified = false;
|
||||
static std::string g_compression = "";
|
||||
|
||||
static void blend(const Image& normal, const Image& detail, Image& output);
|
||||
static void blend(const LinearImage& normal, const LinearImage& detail, LinearImage output);
|
||||
|
||||
static void printUsage(const char* name) {
|
||||
std::string execName(utils::Path(name).getName());
|
||||
@@ -159,7 +159,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// make sure we load the normal maps as linear data
|
||||
std::ifstream inputStream(normalMap, std::ios::binary);
|
||||
Image normalImage = ImageDecoder::decode(inputStream, normalMap,
|
||||
LinearImage normalImage = ImageDecoder::decode(inputStream, normalMap,
|
||||
ImageDecoder::ColorSpace::LINEAR);
|
||||
if (!normalImage.isValid()) {
|
||||
std::cerr << "The input normal map is invalid: " << normalMap << std::endl;
|
||||
@@ -168,7 +168,7 @@ int main(int argc, char* argv[]) {
|
||||
inputStream.close();
|
||||
|
||||
inputStream.open(detailMap, std::ios::binary);
|
||||
Image detailImage = ImageDecoder::decode(inputStream, detailMap,
|
||||
LinearImage detailImage = ImageDecoder::decode(inputStream, detailMap,
|
||||
ImageDecoder::ColorSpace::LINEAR);
|
||||
if (!detailImage.isValid()) {
|
||||
std::cerr << "The detail normal map is invalid: " << detailMap << std::endl;
|
||||
@@ -189,9 +189,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
size_t width = normalImage.getWidth();
|
||||
size_t height = normalImage.getHeight();
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[width * height * sizeof(float3)]);
|
||||
Image image(std::move(buffer), width, height, width * sizeof(float3), sizeof(float3));
|
||||
LinearImage image(width, height, 3);
|
||||
|
||||
blend(normalImage, detailImage, image);
|
||||
|
||||
@@ -214,14 +212,14 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
void blend(const Image& normal, const Image& detail, Image& output) {
|
||||
void blend(const LinearImage& normal, const LinearImage& detail, LinearImage output) {
|
||||
const size_t width = output.getWidth();
|
||||
const size_t height = output.getHeight();
|
||||
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
float3* normalRow = static_cast<float3*>(normal.getPixelRef(0, y));
|
||||
float3* detailRow = static_cast<float3*>(detail.getPixelRef(0, y));
|
||||
float3* outputRow = static_cast<float3*>(output.getPixelRef(0, y));
|
||||
auto normalRow = normal.get<float3>(0, y);
|
||||
auto detailRow = detail.get<float3>(0, y);
|
||||
auto outputRow = output.get<float3>(0, y);
|
||||
|
||||
for (size_t x = 0; x < width; x++, normalRow++, detailRow++, outputRow++) {
|
||||
// Reoriented Normal Mapping
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include <math/vec3.h>
|
||||
|
||||
#include <image/ImageOps.h>
|
||||
|
||||
#include <imageio/ImageDecoder.h>
|
||||
#include <imageio/ImageEncoder.h>
|
||||
|
||||
@@ -176,7 +178,7 @@ inline bool isPOT(size_t x) {
|
||||
}
|
||||
|
||||
float solveVMF(const float2& pos, const size_t sampleCount, const float roughness,
|
||||
const Image& normal) {
|
||||
const LinearImage& normal) {
|
||||
|
||||
float3 averageNormal(0.0f);
|
||||
float2 topLeft(-float(sampleCount) / 2.0f + 0.5f);
|
||||
@@ -185,8 +187,7 @@ float solveVMF(const float2& pos, const size_t sampleCount, const float roughnes
|
||||
for (size_t x = 0; x < sampleCount; x++) {
|
||||
float2 offset(topLeft + float2(x, y));
|
||||
float2 samplePos(floor(pos + offset) + 0.5f);
|
||||
float3 sampleNormal = *static_cast<float3*>(
|
||||
normal.getPixelRef(size_t(samplePos.x), size_t(samplePos.y)));
|
||||
float3 sampleNormal = *normal.get<float3>(size_t(samplePos.x), size_t(samplePos.y));
|
||||
sampleNormal = sampleNormal * 2.0f - 1.0f;
|
||||
|
||||
averageNormal += normalize(sampleNormal);
|
||||
@@ -209,13 +210,13 @@ float solveVMF(const float2& pos, const size_t sampleCount, const float roughnes
|
||||
return std::sqrt(roughness * roughness + (2.0f / kappa));
|
||||
}
|
||||
|
||||
void prefilter(const Image& normal, const size_t mipLevel, Image& output) {
|
||||
void prefilter(const LinearImage& normal, const size_t mipLevel, LinearImage& output) {
|
||||
const size_t width = output.getWidth();
|
||||
const size_t height = output.getHeight();
|
||||
const size_t sampleCount = 1u << mipLevel;
|
||||
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
auto* outputRow = static_cast<float3*>(output.getPixelRef(0, y));
|
||||
auto outputRow = output.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++, outputRow++) {
|
||||
const float2 uv = (float2(x, y) + 0.5f) / float2(width, height);
|
||||
const float2 pos = uv * normal.getWidth();
|
||||
@@ -226,15 +227,16 @@ void prefilter(const Image& normal, const size_t mipLevel, Image& output) {
|
||||
}
|
||||
|
||||
template<bool FIRST_MIP>
|
||||
void prefilter(const Image& normal, const Image& roughness, const size_t mipLevel, Image& output) {
|
||||
void prefilter(const LinearImage& normal, const LinearImage& roughness, const size_t mipLevel,
|
||||
LinearImage& output) {
|
||||
const size_t width = output.getWidth();
|
||||
const size_t height = output.getHeight();
|
||||
const size_t sampleCount = 1u << mipLevel;
|
||||
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
auto* outputRow = static_cast<float3*>(output.getPixelRef(0, y));
|
||||
auto outputRow = output.get<float3>(0, y);
|
||||
for (size_t x = 0; x < width; x++, outputRow++) {
|
||||
const float3* data = static_cast<float3*>(roughness.getPixelRef(x, y));
|
||||
auto data = roughness.get<float3>(x, y);
|
||||
if (FIRST_MIP) {
|
||||
*outputRow = *data;
|
||||
} else {
|
||||
@@ -265,7 +267,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// make sure we load the normal maps as linear data
|
||||
std::ifstream inputStream(normalMap, std::ios::binary);
|
||||
Image normalImage = ImageDecoder::decode(inputStream, normalMap,
|
||||
LinearImage normalImage = ImageDecoder::decode(inputStream, normalMap,
|
||||
ImageDecoder::ColorSpace::LINEAR);
|
||||
inputStream.close();
|
||||
|
||||
@@ -281,8 +283,8 @@ int main(int argc, char* argv[]) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Image roughnessImage;
|
||||
std::vector<Image> mipImages;
|
||||
LinearImage roughnessImage;
|
||||
std::vector<LinearImage> mipImages;
|
||||
bool hasRoughnessMap = false;
|
||||
|
||||
if (!g_roughnessMap.isEmpty()) {
|
||||
@@ -330,13 +332,13 @@ int main(int argc, char* argv[]) {
|
||||
const size_t height = hasRoughnessMap ? roughnessImage.getHeight() : normalImage.getHeight();
|
||||
const size_t mipLevels = size_t(std::log2f(width)) + 1;
|
||||
|
||||
size_t channels = 3;
|
||||
bool exportGrayscale = false;
|
||||
switch (g_format) {
|
||||
case ImageEncoder::Format::DDS:
|
||||
case ImageEncoder::Format::DDS_LINEAR:
|
||||
case ImageEncoder::Format::PNG:
|
||||
case ImageEncoder::Format::PNG_LINEAR:
|
||||
channels = 1;
|
||||
exportGrayscale = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -344,23 +346,21 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
if (hasRoughnessMap) {
|
||||
mipImages.push_back(std::move(roughnessImage));
|
||||
Image* prevMip = &mipImages.at(0);
|
||||
LinearImage* prevMip = &mipImages.at(0);
|
||||
|
||||
for (size_t i = 1; i <= mipLevels; i++) {
|
||||
const size_t w = width >> i;
|
||||
const size_t h = height >> i;
|
||||
|
||||
const size_t size = w * h * sizeof(float3);
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]);
|
||||
Image image(std::move(buffer), w, h, w * sizeof(float3), sizeof(float3), channels);
|
||||
LinearImage image(w, h, 3);
|
||||
|
||||
for (size_t y = 0; y < h; y++) {
|
||||
auto* dst = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
auto dst = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < w; x++, dst++) {
|
||||
float3 aa = *static_cast<float3*>(prevMip->getPixelRef(x * 2, y * 2));
|
||||
float3 ba = *static_cast<float3*>(prevMip->getPixelRef(x * 2 + 1, y * 2));
|
||||
float3 ab = *static_cast<float3*>(prevMip->getPixelRef(x * 2, y * 2 + 1));
|
||||
float3 bb = *static_cast<float3*>(prevMip->getPixelRef(x * 2 + 1, y * 2 + 1));
|
||||
float3 aa = *prevMip->get<float3>(x * 2, y * 2);
|
||||
float3 ba = *prevMip->get<float3>(x * 2 + 1, y * 2);
|
||||
float3 ab = *prevMip->get<float3>(x * 2, y * 2 + 1);
|
||||
float3 bb = *prevMip->get<float3>(x * 2 + 1, y * 2 + 1);
|
||||
*dst = (aa + ba + ab + bb) / 4.0f;
|
||||
}
|
||||
}
|
||||
@@ -376,23 +376,22 @@ int main(int argc, char* argv[]) {
|
||||
JobSystem::Job* parent = js.createJob();
|
||||
for (size_t i = 0; i < mipLevels; i++) {
|
||||
JobSystem::Job* mip = jobs::createJob(js, parent,
|
||||
[&normalImage, &mipImages, outputMap, i, width, height, channels, hasRoughnessMap]() {
|
||||
[&normalImage, &mipImages, outputMap, i, width, height, exportGrayscale, hasRoughnessMap]() {
|
||||
const size_t w = width >> i;
|
||||
const size_t h = height >> i;
|
||||
|
||||
const size_t size = w * h * sizeof(float3);
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]);
|
||||
Image image(std::move(buffer), w, h, w * sizeof(float3), sizeof(float3), channels);
|
||||
LinearImage image(w, h, 3);
|
||||
|
||||
if (i == 0) {
|
||||
if (hasRoughnessMap) {
|
||||
if (mipImages.at(0).getBytesPerRow() == image.getBytesPerRow()) {
|
||||
memcpy(image.getData(), mipImages.at(0).getData(), size);
|
||||
if (mipImages.at(0).getWidth() == image.getWidth()) {
|
||||
const size_t size = image.getWidth() * image.getHeight() * 12;
|
||||
memcpy(image.getPixelRef(), mipImages.at(0).getPixelRef(), size);
|
||||
} else {
|
||||
prefilter<true>(normalImage, mipImages.at(0), 0, image);
|
||||
}
|
||||
} else {
|
||||
std::fill_n(static_cast<float3*>(image.getData()), w * h, float3(g_roughness));
|
||||
std::fill_n(image.get<float3>(), w * h, float3(g_roughness));
|
||||
}
|
||||
} else {
|
||||
if (hasRoughnessMap) {
|
||||
@@ -410,13 +409,16 @@ int main(int argc, char* argv[]) {
|
||||
std::ofstream outputStream(out, std::ios::binary | std::ios::trunc);
|
||||
if (!outputStream.good()) {
|
||||
std::cerr << "The output file cannot be opened: " << out << std::endl;
|
||||
} else {
|
||||
ImageEncoder::encode(outputStream, g_format, image, g_compression, out.getPath());
|
||||
outputStream.close();
|
||||
if (!outputStream.good()) {
|
||||
std::cerr << "An error occurred while writing the output file: " << out <<
|
||||
std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (exportGrayscale) {
|
||||
image = extractChannel(image, 0);
|
||||
}
|
||||
ImageEncoder::encode(outputStream, g_format, image, g_compression, out.getPath());
|
||||
outputStream.close();
|
||||
if (!outputStream.good()) {
|
||||
std::cerr << "An error occurred while writing the output file: " << out <<
|
||||
std::endl;
|
||||
}
|
||||
});
|
||||
js.run(mip);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <math/scalar.h>
|
||||
#include <math/vec3.h>
|
||||
|
||||
#include <image/LinearImage.h>
|
||||
#include <imageio/ImageEncoder.h>
|
||||
|
||||
#include <utils/JobSystem.h>
|
||||
@@ -83,7 +84,7 @@ static float angleBetween(float thetav, float phiv, float theta, float phi) {
|
||||
return acosf(cosGamma);
|
||||
}
|
||||
|
||||
static void generateSky(const Image& image) {
|
||||
static void generateSky(LinearImage image) {
|
||||
printf("Sky parameters\n");
|
||||
printf(" Elevation: %.2f°\n", g_elevation * 180.0 * M_1_PI);
|
||||
printf(" Azimuth: %.2f°\n", g_azimuth * 180.0 * M_1_PI);
|
||||
@@ -121,7 +122,7 @@ static void generateSky(const Image& image) {
|
||||
|
||||
size_t y0 = size_t(d);
|
||||
for (size_t y = y0; y < y0 + c; y++) {
|
||||
float3* UTILS_RESTRICT data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
float3* UTILS_RESTRICT data = image.get<float3>(0, y);
|
||||
|
||||
float v = (y + 0.5f) / h;
|
||||
float theta = float(M_PI * v);
|
||||
@@ -193,7 +194,7 @@ static void generateSky(const Image& image) {
|
||||
const size_t h = image.getHeight();
|
||||
|
||||
for (size_t y = 0; y < h; y++) {
|
||||
float3* UTILS_RESTRICT data = static_cast<float3*>(image.getPixelRef(0, y));
|
||||
float3* UTILS_RESTRICT data = image.get<float3>(0, y);
|
||||
for (size_t x = 0; x < w; x++, data++) {
|
||||
*data *= hdrScale;
|
||||
if (g_tonemap) {
|
||||
@@ -389,10 +390,9 @@ int main(int argc, char* argv[]) {
|
||||
const uint32_t height = std::max(1u, g_outputWidth >> 1);
|
||||
|
||||
// allocate map
|
||||
const size_t size = width * height * sizeof(float3);
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]);
|
||||
Image image(std::move(buffer), width, height, width * sizeof(float3), sizeof(float3), 3);
|
||||
LinearImage image(width, height, 3);
|
||||
|
||||
// render the sky and sun disk
|
||||
generateSky(image);
|
||||
|
||||
// write the environment map to disk
|
||||
|
||||
Reference in New Issue
Block a user