summaryrefslogtreecommitdiffstats
path: root/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTextureHDR.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTextureHDR.cpp')
-rw-r--r--src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTextureHDR.cpp255
1 files changed, 255 insertions, 0 deletions
diff --git a/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTextureHDR.cpp b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTextureHDR.cpp
new file mode 100644
index 00000000..defff295
--- /dev/null
+++ b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTextureHDR.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+// ==========================================================
+// Radiance RGBE .HDR Loader
+// Decodes Radiance RGBE HDR image into FP16 texture buffer.
+//
+// Implementation by
+// Parashar Krishnamachari (parashark@nvidia.com)
+//
+// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
+// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
+// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
+// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
+// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
+// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
+// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+// THIS DISCLAIMER.
+//
+// Use at your own risk!
+// ==========================================================
+
+#include "Qt3DSRenderLoadedTextureFreeImageCompat.h"
+#include "render/Qt3DSRenderBaseTypes.h"
+
+typedef unsigned char RGBE[4];
+#define R 0
+#define G 1
+#define B 2
+#define E 3
+
+#define MINELEN 8 // minimum scanline length for encoding
+#define MAXELEN 0x7fff // maximum scanline length for encoding
+
+static int s_format_id;
+
+static float convertComponent(int exponent, int val)
+{
+ float v = val / (256.0f);
+ float d = powf(2.0f, (float)exponent - 128.0f);
+ return v * d;
+}
+
+static void decrunchScanlineOld(FreeImageIO *io, fi_handle handle, RGBE *scanline, int width)
+{
+ int i;
+ int rshift = 0;
+
+ while (width > 0) {
+ io->read_proc(scanline, 4, 1, handle);
+
+ // The older version of RLE encodes the length in the exponent.
+ // and marks a run with 1, 1, 1 in RGB. This is differentiated from
+ // a raw value of 1, 1, 1, by having a exponent of 0;
+ if (scanline[0][R] == 1 && scanline[0][G] == 1 && scanline[0][B] == 1) {
+ for (i = (scanline[0][E] << rshift); i > 0; --i) {
+ memcpy(&scanline[0][0], &scanline[-1][0], 4);
+ ++scanline;
+ --width;
+ }
+ rshift += 8;
+ } else {
+ ++scanline;
+ --width;
+ rshift = 0;
+ }
+ }
+}
+
+static void decrunchScanline(FreeImageIO *io, fi_handle handle, RGBE *scanline, int width)
+{
+ if ((width < MINELEN) || (width > MAXELEN)) {
+ decrunchScanlineOld(io, handle, scanline, width);
+ return;
+ }
+
+ char c;
+ io->read_proc(&c, 1, 1, handle);
+ if (c != 2) {
+ io->seek_proc(handle, -1, SEEK_CUR);
+ decrunchScanlineOld(io, handle, scanline, width);
+ return;
+ }
+
+ io->read_proc(&(scanline[0][G]), 1, 1, handle);
+ io->read_proc(&(scanline[0][B]), 1, 1, handle);
+ io->read_proc(&c, 1, 1, handle);
+
+ if (scanline[0][G] != 2 || scanline[0][B] & 128) {
+ scanline[0][R] = 2;
+ scanline[0][E] = c;
+ decrunchScanlineOld(io, handle, scanline + 1, width - 1);
+ }
+
+ // RLE-encoded version does a separate buffer for each channel per scanline
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < width;) {
+ unsigned char code, val;
+ io->read_proc(&code, 1, 1, handle);
+ if (code
+ > 128) // RLE-encoded run... read 1 value and copy it forward for some n count.
+ {
+ code &= 127;
+ io->read_proc(&val, 1, 1, handle);
+ while (code--)
+ scanline[j++][i] = val;
+ } else // Not a run, so we read it as raw data
+ {
+ // Note -- we store each pixel in memory 4 bytes apart, so we can't just
+ // do one long read.
+ while (code--)
+ io->read_proc(&(scanline[j++][i]), 1, 1, handle);
+ }
+ }
+ }
+}
+
+static void decodeScanlineToTexture(RGBE *scanline, int width, void *outBuf, QT3DSU32 offset,
+ NVRenderTextureFormats::Enum inFormat)
+{
+ float rgbaF32[4];
+
+ for (int i = 0; i < width; ++i) {
+ rgbaF32[R] = convertComponent(scanline[i][E], scanline[i][R]);
+ rgbaF32[G] = convertComponent(scanline[i][E], scanline[i][G]);
+ rgbaF32[B] = convertComponent(scanline[i][E], scanline[i][B]);
+ rgbaF32[3] = 1.0f;
+
+ QT3DSU8 *target = reinterpret_cast<QT3DSU8 *>(outBuf);
+ target += offset;
+ NVRenderTextureFormats::encodeToPixel(
+ rgbaF32, target, i * NVRenderTextureFormats::getSizeofFormat(inFormat), inFormat);
+ }
+}
+
+static FIBITMAP *DoLoadHDR(FreeImageIO *io, fi_handle handle,
+ NVRenderTextureFormats::Enum inFormat = NVRenderTextureFormats::RGB32F)
+{
+ FIBITMAP *dib = NULL;
+ try {
+ if (handle != NULL) {
+ char str[200];
+ int i;
+
+ // Make sure it's a Radiance RGBE file
+ io->read_proc(str, 10, 1, handle);
+ if (memcmp(str, "#?RADIANCE", 10)) {
+ throw "Invalid HDR file";
+ }
+
+ io->seek_proc(handle, 1, SEEK_CUR);
+
+ // Get the command string (it's not really important for us; We're always assuming
+ // 32bit_rle_rgbe is the format
+ // we're just reading it to skip ahead the correct number of bytes).
+ i = 0;
+ char c = 0, prevC;
+ do {
+ prevC = c;
+ io->read_proc(&c, 1, 1, handle);
+ str[i++] = c;
+ } while (!(c == 0xa && prevC == 0xa));
+
+ // Get the resolution string (it will be NULL-terminated for us)
+ char res[200];
+ i = 0;
+ do {
+ io->read_proc(&c, 1, 1, handle);
+ res[i++] = c;
+ } while (c != 0xa);
+ res[i] = 0;
+
+ int width, height;
+ if (!sscanf(res, "-Y %d +X %d", &height, &width)) {
+ throw "Error encountered while loading HDR stream : could not determine image "
+ "resolution!";
+ }
+ int bytesPerPixel = NVRenderTextureFormats::getSizeofFormat(inFormat);
+ dib = FreeImage_Allocate(width, height, bytesPerPixel * 8, io);
+ if (dib == NULL) {
+ throw "DIB allocation failed";
+ }
+
+ dib->format = inFormat;
+ dib->components = NVRenderTextureFormats::getNumberOfComponent(inFormat);
+
+ // Allocate a scanline worth of RGBE data
+ RGBE *scanline = new RGBE[width];
+ if (!scanline) {
+ throw "Error encountered while loading HDR stream : could not buffer scanlines!";
+ }
+
+ // Go through all the scanlines
+ for (int y = 0; y < height; ++y) {
+ QT3DSU32 byteOfs = (height - 1 - y) * width * bytesPerPixel;
+ decrunchScanline(io, handle, scanline, width);
+ decodeScanlineToTexture(scanline, width, dib->data, byteOfs, inFormat);
+ }
+ }
+ return dib;
+ } catch (const char *message) {
+ if (dib) {
+ FreeImage_Unload(dib);
+ }
+ if (message) {
+ FreeImage_OutputMessageProc(s_format_id, message, io);
+ }
+ }
+
+ return NULL;
+}
+
+SLoadedTexture *SLoadedTexture::LoadHDR(ISeekableIOStream &inStream, NVFoundationBase &inFnd,
+ qt3ds::render::NVRenderContextType renderContextType)
+{
+ FreeImageIO theIO(inFnd.getAllocator(), inFnd);
+ SLoadedTexture *retval = nullptr;
+ if (renderContextType == qt3ds::render::NVRenderContextValues::GLES2)
+ retval = DoLoadHDR(&theIO, &inStream, NVRenderTextureFormats::RGBA8);
+ else
+ retval = DoLoadHDR(&theIO, &inStream, NVRenderTextureFormats::RGBA16F);
+
+
+ // Let's just assume we don't support this just yet.
+ // if ( retval )
+ // retval->FreeImagePostProcess( inFlipY );
+ return retval;
+}