summaryrefslogtreecommitdiffstats
path: root/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp')
-rw-r--r--src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp704
1 files changed, 704 insertions, 0 deletions
diff --git a/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp
new file mode 100644
index 00000000..3365a2ce
--- /dev/null
+++ b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp
@@ -0,0 +1,704 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 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$
+**
+****************************************************************************/
+#include "Qt3DSRenderLoadedTexture.h"
+#include "foundation/IOStreams.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "Qt3DSDMWindowsCompatibility.h"
+#include "Qt3DSRenderInputStreamFactory.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "Qt3DSRenderImageScaler.h"
+#include "Qt3DSTextRenderer.h"
+#include <QImage>
+
+using namespace qt3ds::render;
+
+SLoadedTexture *SLoadedTexture::LoadQImage(const QString &inPath, QT3DSI32 flipVertical,
+ NVFoundationBase &fnd,
+ NVRenderContextType renderContextType)
+{
+ Q_UNUSED(flipVertical)
+ Q_UNUSED(renderContextType)
+ SLoadedTexture *retval(NULL);
+ NVAllocatorCallback &alloc(fnd.getAllocator());
+ QImage image(inPath);
+ image = image.mirrored();
+ image = image.rgbSwapped();
+ retval = QT3DS_NEW(alloc, SLoadedTexture)(alloc);
+ retval->width = image.width();
+ retval->height = image.height();
+ retval->components = image.pixelFormat().channelCount();
+ retval->image = image;
+ retval->data = (void*)retval->image.bits();
+ retval->dataSizeInBytes = image.byteCount();
+ retval->setFormatFromComponents();
+ return retval;
+}
+
+
+namespace {
+
+/**
+ !!Large section of code ripped from FreeImage!!
+
+*/
+// ----------------------------------------------------------
+// Structures used by DXT textures
+// ----------------------------------------------------------
+typedef QT3DSU8 BYTE;
+typedef QT3DSU16 WORD;
+
+typedef struct tagColor8888
+{
+ BYTE b;
+ BYTE g;
+ BYTE r;
+ BYTE a;
+} Color8888;
+
+typedef struct tagColor565
+{
+ WORD b : 5;
+ WORD g : 6;
+ WORD r : 5;
+} Color565;
+
+typedef struct tagDXTColBlock
+{
+ Color565 colors[2];
+ BYTE row[4];
+} DXTColBlock;
+
+typedef struct tagDXTAlphaBlockExplicit
+{
+ WORD row[4];
+} DXTAlphaBlockExplicit;
+
+typedef struct tagDXTAlphaBlock3BitLinear
+{
+ BYTE alpha[2];
+ BYTE data[6];
+} DXTAlphaBlock3BitLinear;
+
+typedef struct tagDXT1Block
+{
+ DXTColBlock color;
+} DXT1Block;
+
+typedef struct tagDXT3Block
+{ // also used by dxt2
+ DXTAlphaBlockExplicit alpha;
+ DXTColBlock color;
+} DXT3Block;
+
+typedef struct tagDXT5Block
+{ // also used by dxt4
+ DXTAlphaBlock3BitLinear alpha;
+ DXTColBlock color;
+} DXT5Block;
+
+static void GetBlockColors(const DXTColBlock &block, Color8888 colors[4], bool isDXT1)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ colors[i].a = 0xff;
+ colors[i].r = (BYTE)(block.colors[i].r * 0xff / 0x1f);
+ colors[i].g = (BYTE)(block.colors[i].g * 0xff / 0x3f);
+ colors[i].b = (BYTE)(block.colors[i].b * 0xff / 0x1f);
+ }
+
+ WORD *wCol = (WORD *)block.colors;
+ if (wCol[0] > wCol[1] || !isDXT1) {
+ // 4 color block
+ for (i = 0; i < 2; i++) {
+ colors[i + 2].a = 0xff;
+ colors[i + 2].r =
+ (BYTE)((WORD(colors[0].r) * (2 - i) + WORD(colors[1].r) * (1 + i)) / 3);
+ colors[i + 2].g =
+ (BYTE)((WORD(colors[0].g) * (2 - i) + WORD(colors[1].g) * (1 + i)) / 3);
+ colors[i + 2].b =
+ (BYTE)((WORD(colors[0].b) * (2 - i) + WORD(colors[1].b) * (1 + i)) / 3);
+ }
+ } else {
+ // 3 color block, number 4 is transparent
+ colors[2].a = 0xff;
+ colors[2].r = (BYTE)((WORD(colors[0].r) + WORD(colors[1].r)) / 2);
+ colors[2].g = (BYTE)((WORD(colors[0].g) + WORD(colors[1].g)) / 2);
+ colors[2].b = (BYTE)((WORD(colors[0].b) + WORD(colors[1].b)) / 2);
+
+ colors[3].a = 0x00;
+ colors[3].g = 0x00;
+ colors[3].b = 0x00;
+ colors[3].r = 0x00;
+ }
+}
+
+struct DXT_INFO_1
+{
+ typedef DXT1Block Block;
+ enum { isDXT1 = 1, bytesPerBlock = 8 };
+};
+
+struct DXT_INFO_3
+{
+ typedef DXT3Block Block;
+ enum { isDXT1 = 1, bytesPerBlock = 16 };
+};
+
+struct DXT_INFO_5
+{
+ typedef DXT5Block Block;
+ enum { isDXT1 = 1, bytesPerBlock = 16 };
+};
+
+template <class INFO>
+class DXT_BLOCKDECODER_BASE
+{
+protected:
+ Color8888 m_colors[4];
+ const typename INFO::Block *m_pBlock;
+ unsigned m_colorRow;
+
+public:
+ void Setup(const BYTE *pBlock)
+ {
+ m_pBlock = (const typename INFO::Block *)pBlock;
+ GetBlockColors(m_pBlock->color, m_colors, INFO::isDXT1);
+ }
+
+ void SetY(int y) { m_colorRow = m_pBlock->color.row[y]; }
+
+ void GetColor(int x, int y, Color8888 &color)
+ {
+ Q_UNUSED(y)
+ unsigned bits = (m_colorRow >> (x * 2)) & 3;
+ color = m_colors[bits];
+ std::swap(color.r, color.b);
+ }
+};
+
+class DXT_BLOCKDECODER_1 : public DXT_BLOCKDECODER_BASE<DXT_INFO_1>
+{
+public:
+ typedef DXT_INFO_1 INFO;
+};
+
+class DXT_BLOCKDECODER_3 : public DXT_BLOCKDECODER_BASE<DXT_INFO_3>
+{
+public:
+ typedef DXT_BLOCKDECODER_BASE<DXT_INFO_3> base;
+ typedef DXT_INFO_3 INFO;
+
+protected:
+ unsigned m_alphaRow;
+
+public:
+ void SetY(int y)
+ {
+ base::SetY(y);
+ m_alphaRow = m_pBlock->alpha.row[y];
+ }
+
+ void GetColor(int x, int y, Color8888 &color)
+ {
+ base::GetColor(x, y, color);
+ const unsigned bits = (m_alphaRow >> (x * 4)) & 0xF;
+ color.a = (BYTE)((bits * 0xFF) / 0xF);
+ }
+};
+
+class DXT_BLOCKDECODER_5 : public DXT_BLOCKDECODER_BASE<DXT_INFO_5>
+{
+public:
+ typedef DXT_BLOCKDECODER_BASE<DXT_INFO_5> base;
+ typedef DXT_INFO_5 INFO;
+
+protected:
+ unsigned m_alphas[8];
+ unsigned m_alphaBits;
+ int m_offset;
+
+public:
+ void Setup(const BYTE *pBlock)
+ {
+ base::Setup(pBlock);
+
+ const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
+ m_alphas[0] = block.alpha[0];
+ m_alphas[1] = block.alpha[1];
+ if (m_alphas[0] > m_alphas[1]) {
+ // 8 alpha block
+ for (int i = 0; i < 6; i++) {
+ m_alphas[i + 2] = ((6 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 3) / 7;
+ }
+ } else {
+ // 6 alpha block
+ for (int i = 0; i < 4; i++) {
+ m_alphas[i + 2] = ((4 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 2) / 5;
+ }
+ m_alphas[6] = 0;
+ m_alphas[7] = 0xFF;
+ }
+ }
+
+ void SetY(int y)
+ {
+ base::SetY(y);
+ int i = y / 2;
+ const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
+ m_alphaBits = unsigned(block.data[0 + i * 3]) | (unsigned(block.data[1 + i * 3]) << 8)
+ | (unsigned(block.data[2 + i * 3]) << 16);
+ m_offset = (y & 1) * 12;
+ }
+
+ void GetColor(int x, int y, Color8888 &color)
+ {
+ base::GetColor(x, y, color);
+ unsigned bits = (m_alphaBits >> (x * 3 + m_offset)) & 7;
+ color.a = (BYTE)m_alphas[bits];
+ std::swap(color.r, color.b);
+ }
+};
+
+template <class DECODER>
+void DecodeDXTBlock(BYTE *dstData, const BYTE *srcBlock, long dstPitch, int bw, int bh)
+{
+ DECODER decoder;
+ decoder.Setup(srcBlock);
+ for (int y = 0; y < bh; y++) {
+ // Note that this assumes the pointer is pointing to the *last* valid start
+ // row.
+ BYTE *dst = dstData - y * dstPitch;
+ decoder.SetY(y);
+ for (int x = 0; x < bw; x++) {
+ decoder.GetColor(x, y, (Color8888 &)*dst);
+ dst += 4;
+ }
+ }
+}
+
+struct STextureDataWriter
+{
+ QT3DSU32 m_Width;
+ QT3DSU32 m_Height;
+ QT3DSU32 m_Stride;
+ QT3DSU32 m_NumComponents;
+ STextureData &m_TextureData;
+ STextureDataWriter(QT3DSU32 w, QT3DSU32 h, bool hasA, STextureData &inTd, NVAllocatorCallback &alloc)
+ : m_Width(w)
+ , m_Height(h)
+ , m_Stride(hasA ? m_Width * 4 : m_Width * 3)
+ , m_NumComponents(hasA ? 4 : 3)
+ , m_TextureData(inTd)
+ {
+ QT3DSU32 dataSize = m_Stride * m_Height;
+ if (dataSize > m_TextureData.dataSizeInBytes) {
+ alloc.deallocate(m_TextureData.data);
+ m_TextureData.data =
+ alloc.allocate(dataSize, "SLoadedTexture::DecompressDXTImage", __FILE__, __LINE__);
+ m_TextureData.dataSizeInBytes = dataSize;
+ }
+ memZero(m_TextureData.data, m_TextureData.dataSizeInBytes);
+ m_TextureData.format = hasA ? NVRenderTextureFormats::RGBA8 : NVRenderTextureFormats::RGB8;
+ }
+
+ void WritePixel(QT3DSU32 X, QT3DSU32 Y, QT3DSU8 *pixelData)
+ {
+ if (X < m_Width && Y < m_Height) {
+ char *textureData = reinterpret_cast<char *>(m_TextureData.data);
+ QT3DSU32 offset = Y * m_Stride + X * m_NumComponents;
+
+ for (QT3DSU32 idx = 0; idx < m_NumComponents; ++idx)
+ QT3DS_ASSERT(textureData[offset + idx] == 0);
+
+ memCopy(textureData + offset, pixelData, m_NumComponents);
+ }
+ }
+
+ // Incoming pixels are assumed to be RGBA or RGBX, 32 bit in any case
+ void WriteBlock(QT3DSU32 X, QT3DSU32 Y, QT3DSU32 width, QT3DSU32 height, QT3DSU8 *pixelData)
+ {
+ QT3DSU32 offset = 0;
+ for (QT3DSU32 yidx = 0; yidx < height; ++yidx) {
+ for (QT3DSU32 xidx = 0; xidx < width; ++xidx, offset += 4) {
+ WritePixel(X + xidx, Y + (height - yidx - 1), pixelData + offset);
+ }
+ }
+ }
+ bool Finished() { return false; }
+};
+
+struct STextureAlphaScanner
+{
+ bool &m_Alpha;
+
+ STextureAlphaScanner(bool &inAlpha)
+ : m_Alpha(inAlpha)
+ {
+ }
+
+ void WriteBlock(QT3DSU32 X, QT3DSU32 Y, QT3DSU32 width, QT3DSU32 height, QT3DSU8 *pixelData)
+ {
+ Q_UNUSED(X)
+ Q_UNUSED(Y)
+ QT3DSU32 offset = 0;
+ for (QT3DSU32 yidx = 0; yidx < height; ++yidx) {
+ for (QT3DSU32 xidx = 0; xidx < width; ++xidx, offset += 4) {
+ if (pixelData[offset + 3] < 255)
+ m_Alpha = true;
+ }
+ }
+ }
+
+ // If we detect alpha we can stop right there.
+ bool Finished() { return m_Alpha; }
+};
+// Scan the dds image's mipmap 0 level for alpha.
+template <class DECODER, class TWriterType>
+static void DecompressDDS(void *inSrc, QT3DSU32 inDataSize, QT3DSU32 inWidth, QT3DSU32 inHeight,
+ TWriterType ioWriter)
+{
+ typedef typename DECODER::INFO INFO;
+ typedef typename INFO::Block Block;
+ (void)inDataSize;
+
+ const QT3DSU8 *pbSrc = (const QT3DSU8 *)inSrc;
+ // Each DX block is composed of 16 pixels. Free image decodes those
+ // pixels into a 4x4 block of data.
+ QT3DSU8 pbDstData[4 * 4 * 4];
+ // The decoder decodes backwards
+ // So we need to point to the last line.
+ QT3DSU8 *pbDst = pbDstData + 48;
+
+ int width = (int)inWidth;
+ int height = (int)inHeight;
+ int lineStride = 16;
+ for (int y = 0; y < height && ioWriter.Finished() == false; y += 4) {
+ int yPixels = NVMin(height - y, 4);
+ for (int x = 0; x < width && ioWriter.Finished() == false; x += 4) {
+ int xPixels = NVMin(width - x, 4);
+ DecodeDXTBlock<DECODER>(pbDst, pbSrc, lineStride, xPixels, yPixels);
+ pbSrc += INFO::bytesPerBlock;
+ ioWriter.WriteBlock(x, y, xPixels, yPixels, pbDstData);
+ }
+ }
+}
+
+bool ScanDDSForAlpha(Qt3DSDDSImage *dds)
+{
+ bool hasAlpha = false;
+ switch (dds->format) {
+ case qt3ds::render::NVRenderTextureFormats::RGBA_DXT1:
+ DecompressDDS<DXT_BLOCKDECODER_1>(dds->data[0], dds->size[0], dds->mipwidth[0],
+ dds->mipheight[0], STextureAlphaScanner(hasAlpha));
+ break;
+ case qt3ds::render::NVRenderTextureFormats::RGBA_DXT3:
+ DecompressDDS<DXT_BLOCKDECODER_3>(dds->data[0], dds->size[0], dds->mipwidth[0],
+ dds->mipheight[0], STextureAlphaScanner(hasAlpha));
+ break;
+ case qt3ds::render::NVRenderTextureFormats::RGBA_DXT5:
+ DecompressDDS<DXT_BLOCKDECODER_5>(dds->data[0], dds->size[0], dds->mipwidth[0],
+ dds->mipheight[0], STextureAlphaScanner(hasAlpha));
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ return hasAlpha;
+}
+
+bool ScanImageForAlpha(const void *inData, QT3DSU32 inWidth, QT3DSU32 inHeight, QT3DSU32 inPixelSizeInBytes,
+ QT3DSU8 inAlphaSizeInBits)
+{
+ const QT3DSU8 *rowPtr = reinterpret_cast<const QT3DSU8 *>(inData);
+ bool hasAlpha = false;
+ if (inAlphaSizeInBits == 0)
+ return hasAlpha;
+ if (inPixelSizeInBytes != 2 && inPixelSizeInBytes != 4) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ if (inAlphaSizeInBits > 8) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+
+ QT3DSU32 alphaRightShift = inPixelSizeInBytes * 8 - inAlphaSizeInBits;
+ QT3DSU32 maxAlphaValue = (1 << inAlphaSizeInBits) - 1;
+
+ for (QT3DSU32 rowIdx = 0; rowIdx < inHeight && hasAlpha == false; ++rowIdx) {
+ for (QT3DSU32 idx = 0; idx < inWidth && hasAlpha == false;
+ ++idx, rowPtr += inPixelSizeInBytes) {
+ QT3DSU32 pixelValue = 0;
+ if (inPixelSizeInBytes == 2)
+ pixelValue = *(reinterpret_cast<const QT3DSU16 *>(rowPtr));
+ else
+ pixelValue = *(reinterpret_cast<const QT3DSU32 *>(rowPtr));
+ pixelValue = pixelValue >> alphaRightShift;
+ if (pixelValue < maxAlphaValue)
+ hasAlpha = true;
+ }
+ }
+ return hasAlpha;
+}
+}
+
+SLoadedTexture::~SLoadedTexture()
+{
+ if (dds) {
+ if (dds->dataBlock)
+ QT3DS_FREE(m_Allocator, dds->dataBlock);
+
+ QT3DS_FREE(m_Allocator, dds);
+ } else if (data && image.byteCount() <= 0) {
+ m_Allocator.deallocate(data);
+ }
+ if (m_Palette)
+ m_Allocator.deallocate(m_Palette);
+ if (m_TransparencyTable)
+ m_Allocator.deallocate(m_TransparencyTable);
+}
+
+void SLoadedTexture::release()
+{
+ NVAllocatorCallback *theAllocator(&m_Allocator);
+ this->~SLoadedTexture();
+ theAllocator->deallocate(this);
+}
+
+bool SLoadedTexture::ScanForTransparency()
+{
+ switch (format) {
+ case NVRenderTextureFormats::SRGB8A8:
+ case NVRenderTextureFormats::RGBA8:
+ if (!data) { // dds
+ return true;
+ } else {
+ return ScanImageForAlpha(data, width, height, 4, 8);
+ }
+ break;
+ // Scan the image.
+ case NVRenderTextureFormats::SRGB8:
+ case NVRenderTextureFormats::RGB8:
+ return false;
+ break;
+ case NVRenderTextureFormats::RGB565:
+ return false;
+ break;
+ case NVRenderTextureFormats::RGBA5551:
+ if (!data) { // dds
+ return true;
+ } else {
+ return ScanImageForAlpha(data, width, height, 2, 1);
+ }
+ break;
+ case NVRenderTextureFormats::Alpha8:
+ return true;
+ break;
+ case NVRenderTextureFormats::Luminance8:
+ return false;
+ break;
+ case NVRenderTextureFormats::LuminanceAlpha8:
+ if (!data) { // dds
+ return true;
+ } else {
+ return ScanImageForAlpha(data, width, height, 2, 8);
+ }
+ break;
+ case NVRenderTextureFormats::RGB_DXT1:
+ return false;
+ break;
+ case NVRenderTextureFormats::RGBA_DXT3:
+ case NVRenderTextureFormats::RGBA_DXT1:
+ case NVRenderTextureFormats::RGBA_DXT5:
+ if (dds) {
+ return ScanDDSForAlpha(dds);
+ } else {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ break;
+ case NVRenderTextureFormats::RGB9E5:
+ return false;
+ break;
+ case NVRenderTextureFormats::RG32F:
+ case NVRenderTextureFormats::RGB32F:
+ case NVRenderTextureFormats::RGBA16F:
+ case NVRenderTextureFormats::RGBA32F:
+ // PKC TODO : For now, since IBL will be the main consumer, we'll just pretend there's no
+ // alpha.
+ // Need to do a proper scan down the line, but doing it for floats is a little different
+ // from
+ // integer scans.
+ return false;
+ break;
+ default:
+ break;
+ }
+ QT3DS_ASSERT(false);
+ return false;
+}
+
+void SLoadedTexture::EnsureMultiplerOfFour(NVFoundationBase &inFoundation, const char *inPath)
+{
+ if (width % 4 || height % 4) {
+ qCWarning(PERF_WARNING,
+ "Image %s has non multiple of four width or height; perf hit for scaling", inPath);
+ if (data) {
+ QT3DSU32 newWidth = ITextRenderer::NextMultipleOf4(width);
+ QT3DSU32 newHeight = ITextRenderer::NextMultipleOf4(height);
+ QT3DSU32 newDataSize = newWidth * newHeight * components;
+ NVAllocatorCallback &theAllocator(inFoundation.getAllocator());
+ QT3DSU8 *newData = (QT3DSU8 *)(theAllocator.allocate(newDataSize, "Scaled Image Data",
+ __FILE__, __LINE__));
+ CImageScaler theScaler(theAllocator);
+ if (components == 4) {
+ theScaler.FastExpandRowsAndColumns((unsigned char *)data, width, height, newData,
+ newWidth, newHeight);
+ } else
+ theScaler.ExpandRowsAndColumns((unsigned char *)data, width, height, newData,
+ newWidth, newHeight, components);
+
+ theAllocator.deallocate(data);
+ data = newData;
+ width = newWidth;
+ height = newHeight;
+ dataSizeInBytes = newDataSize;
+ }
+ }
+}
+
+STextureData SLoadedTexture::DecompressDXTImage(int inMipMapIdx, STextureData *inOptLastImage)
+{
+ STextureData retval;
+ if (inOptLastImage)
+ retval = *inOptLastImage;
+
+ if (dds == NULL || inMipMapIdx >= dds->numMipmaps) {
+ QT3DS_ASSERT(false);
+ ReleaseDecompressedTexture(retval);
+ return STextureData();
+ }
+ char *srcData = (char *)dds->data[inMipMapIdx];
+ int srcDataSize = dds->size[inMipMapIdx];
+ QT3DSU32 imgWidth = (QT3DSU32)dds->mipwidth[inMipMapIdx];
+ QT3DSU32 imgHeight = (QT3DSU32)dds->mipheight[inMipMapIdx];
+
+ switch (format) {
+ case NVRenderTextureFormats::RGB_DXT1:
+ DecompressDDS<DXT_BLOCKDECODER_1>(
+ srcData, srcDataSize, imgWidth, imgHeight,
+ STextureDataWriter(imgWidth, imgHeight, false, retval, m_Allocator));
+ break;
+ case NVRenderTextureFormats::RGBA_DXT1:
+ DecompressDDS<DXT_BLOCKDECODER_1>(
+ srcData, srcDataSize, imgWidth, imgHeight,
+ STextureDataWriter(imgWidth, imgHeight, true, retval, m_Allocator));
+ break;
+ case NVRenderTextureFormats::RGBA_DXT3:
+ DecompressDDS<DXT_BLOCKDECODER_3>(
+ srcData, srcDataSize, imgWidth, imgHeight,
+ STextureDataWriter(imgWidth, imgHeight, true, retval, m_Allocator));
+ break;
+ case NVRenderTextureFormats::RGBA_DXT5:
+ DecompressDDS<DXT_BLOCKDECODER_5>(
+ srcData, srcDataSize, imgWidth, imgHeight,
+ STextureDataWriter(imgWidth, imgHeight, true, retval, m_Allocator));
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ return retval;
+}
+
+void SLoadedTexture::ReleaseDecompressedTexture(STextureData inImage)
+{
+ if (inImage.data)
+ m_Allocator.deallocate(inImage.data);
+}
+
+#ifndef EA_PLATFORM_WINDOWS
+#define stricmp strcasecmp
+#endif
+
+SLoadedTexture *SLoadedTexture::Load(const QString &inPath, NVFoundationBase &inFoundation,
+ IInputStreamFactory &inFactory, bool inFlipY,
+ NVRenderContextType renderContextType, bool preferKTX)
+{
+ if (inPath.isEmpty())
+ return nullptr;
+
+ // Check KTX path first
+ QString path = inPath;
+ QString ktxSource = inPath;
+ if (preferKTX) {
+ ktxSource = ktxSource.left(ktxSource.lastIndexOf(QLatin1Char('.')));
+ ktxSource.append(QLatin1String(".ktx"));
+ }
+
+ SLoadedTexture *theLoadedImage = nullptr;
+ // We will get invalid error logs of files not found if we don't force quiet mode
+ // If the file is actually missing, it will be logged later (loaded image is null)
+ NVScopedRefCounted<IRefCountedInputStream> theStream(
+ inFactory.GetStreamForFile(preferKTX ? ktxSource : inPath, true));
+ if (!theStream.mPtr) {
+ if (!preferKTX)
+ theStream = inFactory.GetStreamForFile(inPath, true);
+ else
+ return nullptr;
+ } else {
+ path = ktxSource;
+ }
+ QString fileName;
+ inFactory.GetPathForFile(path, fileName, true);
+ if (theStream.mPtr && path.size() > 3) {
+ if (path.endsWith(QLatin1String("png"), Qt::CaseInsensitive)
+ || path.endsWith(QLatin1String("jpg"), Qt::CaseInsensitive)
+ || path.endsWith(QLatin1String("peg"), Qt::CaseInsensitive)) {
+ theLoadedImage = LoadQImage(fileName, inFlipY, inFoundation, renderContextType);
+ } else if (path.endsWith(QLatin1String("dds"), Qt::CaseInsensitive)) {
+ theLoadedImage = LoadDDS(*theStream, inFlipY, inFoundation, renderContextType);
+ } else if (path.endsWith(QLatin1String("gif"), Qt::CaseInsensitive)) {
+ theLoadedImage = LoadGIF(*theStream, !inFlipY, inFoundation, renderContextType);
+ } else if (path.endsWith(QLatin1String("bmp"), Qt::CaseInsensitive)) {
+ theLoadedImage = LoadBMP(*theStream, !inFlipY, inFoundation, renderContextType);
+ } else if (path.endsWith(QLatin1String("hdr"), Qt::CaseInsensitive)) {
+ theLoadedImage = LoadHDR(*theStream, inFoundation, renderContextType);
+ } else if (path.endsWith(QLatin1String("ktx"), Qt::CaseInsensitive)) {
+ theLoadedImage = LoadKTX(*theStream, inFlipY, inFoundation, renderContextType);
+ } else {
+ qCWarning(INTERNAL_ERROR, "Unrecognized image extension: %s", qPrintable(inPath));
+ }
+ }
+
+ return theLoadedImage;
+}