aboutsummaryrefslogtreecommitdiff
path: root/libs/preview_dds_native/src
diff options
context:
space:
mode:
Diffstat (limited to 'libs/preview_dds_native/src')
-rw-r--r--libs/preview_dds_native/src/CMakeLists.txt17
-rw-r--r--libs/preview_dds_native/src/ddsfile.cpp132
-rw-r--r--libs/preview_dds_native/src/ddsfile.h47
-rw-r--r--libs/preview_dds_native/src/ddsformat.cpp619
-rw-r--r--libs/preview_dds_native/src/ddsformat.h200
-rw-r--r--libs/preview_dds_native/src/ddspreview.cpp126
-rw-r--r--libs/preview_dds_native/src/ddspreview.h44
-rw-r--r--libs/preview_dds_native/src/ddswidget.cpp252
-rw-r--r--libs/preview_dds_native/src/ddswidget.h36
9 files changed, 0 insertions, 1473 deletions
diff --git a/libs/preview_dds_native/src/CMakeLists.txt b/libs/preview_dds_native/src/CMakeLists.txt
deleted file mode 100644
index c920d49..0000000
--- a/libs/preview_dds_native/src/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-cmake_minimum_required(VERSION 3.16)
-
-find_package(Qt6 REQUIRED COMPONENTS OpenGL OpenGLWidgets)
-
-file(GLOB preview_dds_native_SOURCES CONFIGURE_DEPENDS
- ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/*.h
-)
-
-add_library(preview_dds_native SHARED ${preview_dds_native_SOURCES})
-mo2_configure_plugin(preview_dds_native NO_SOURCES WARNINGS OFF)
-target_link_libraries(preview_dds_native PRIVATE
- mo2::uibase
- Qt6::OpenGL
- Qt6::OpenGLWidgets
-)
-mo2_install_plugin(preview_dds_native)
diff --git a/libs/preview_dds_native/src/ddsfile.cpp b/libs/preview_dds_native/src/ddsfile.cpp
deleted file mode 100644
index 91dc627..0000000
--- a/libs/preview_dds_native/src/ddsfile.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-#include "ddsfile.h"
-
-#include <QFile>
-
-#include <algorithm>
-#include <cstring>
-
-bool DDSFile::loadFromFile(const QString& path)
-{
- QFile file(path);
- if (!file.open(QIODevice::ReadOnly)) {
- return false;
- }
- return parse(file.readAll());
-}
-
-bool DDSFile::loadFromData(const QByteArray& data)
-{
- return parse(data);
-}
-
-bool DDSFile::parse(const QByteArray& data)
-{
- const char* ptr = data.constData();
- int offset = 0;
- int size = data.size();
-
- // Magic number
- if (size < 4)
- return false;
- uint32_t magic;
- std::memcpy(&magic, ptr + offset, 4);
- offset += 4;
- if (magic != DDS_MAGIC)
- return false;
-
- // DDS header
- if (size - offset < static_cast<int>(sizeof(DDSHeader)))
- return false;
- DDSHeader header;
- std::memcpy(&header, ptr + offset, sizeof(DDSHeader));
- offset += sizeof(DDSHeader);
-
- if (header.dwSize != 124)
- return false;
-
- // DXT10 extended header
- DDSHeaderDXT10 dxt10{};
- bool hasDXT10 = false;
- if ((header.ddspf.dwFlags & DDPF_FOURCC) &&
- header.ddspf.dwFourCC == makeFourCC('D', 'X', '1', '0')) {
- if (size - offset < static_cast<int>(sizeof(DDSHeaderDXT10)))
- return false;
- std::memcpy(&dxt10, ptr + offset, sizeof(DDSHeaderDXT10));
- offset += sizeof(DDSHeaderDXT10);
- hasDXT10 = true;
- }
-
- m_width = header.dwWidth;
- m_height = header.dwHeight;
-
- // Determine GL format
- m_glFormat = getGLFormat(header.ddspf, hasDXT10 ? &dxt10 : nullptr);
- if (!m_glFormat.valid) {
- return false;
- }
-
- // Determine DXGI format for size calculations
- if (hasDXT10) {
- m_dxgiFormat = dxt10.dxgiFormat;
- } else if (header.ddspf.dwFlags & DDPF_FOURCC) {
- m_dxgiFormat = fourCCToDXGI(header.ddspf.dwFourCC);
- } else {
- m_dxgiFormat = DXGIFormat::UNKNOWN;
- }
-
- // Description
- m_description = formatDescription(header.ddspf, hasDXT10 ? &dxt10 : nullptr);
- m_description +=
- QString(" | %1x%2").arg(m_width).arg(m_height);
-
- // Cubemap detection
- m_cubemap = false;
- int layers = 1;
- if (header.dwCaps2 & DDSCAPS2_CUBEMAP) {
- m_cubemap = true;
- layers = 0;
- if (header.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) layers++;
- if (header.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) layers++;
- if (header.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEY) layers++;
- if (header.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) layers++;
- if (header.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) layers++;
- if (header.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) layers++;
- m_description += " | Cubemap";
- } else {
- m_description += " | 2D";
- }
-
- // Mipmap count
- int mipCount = 1;
- if (header.dwFlags & DDSD_MIPMAPCOUNT) {
- mipCount = std::max(1u, header.dwMipMapCount);
- }
- if (mipCount > 1) {
- m_description += QString(" | %1 mips").arg(mipCount);
- }
-
- // Read pixel data for each face and mip level
- m_faces.resize(layers);
- for (int face = 0; face < layers; ++face) {
- m_faces[face].mips.resize(mipCount);
- uint32_t w = m_width;
- uint32_t h = m_height;
- for (int mip = 0; mip < mipCount; ++mip) {
- uint32_t dataSize = mipDataSize(m_dxgiFormat, header.ddspf, w, h);
- if (offset + static_cast<int>(dataSize) > size) {
- // Truncated file, keep what we have
- m_faces[face].mips.resize(mip);
- break;
- }
- m_faces[face].mips[mip].width = w;
- m_faces[face].mips[mip].height = h;
- m_faces[face].mips[mip].data =
- QByteArray(ptr + offset, static_cast<int>(dataSize));
- offset += dataSize;
- w = std::max(1u, w / 2);
- h = std::max(1u, h / 2);
- }
- }
-
- return !m_faces.isEmpty() && !m_faces[0].mips.isEmpty();
-}
diff --git a/libs/preview_dds_native/src/ddsfile.h b/libs/preview_dds_native/src/ddsfile.h
deleted file mode 100644
index 4242c61..0000000
--- a/libs/preview_dds_native/src/ddsfile.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef DDSFILE_H
-#define DDSFILE_H
-
-#include "ddsformat.h"
-
-#include <QByteArray>
-#include <QString>
-#include <QVector>
-
-struct DDSMipLevel {
- uint32_t width;
- uint32_t height;
- QByteArray data;
-};
-
-struct DDSFace {
- QVector<DDSMipLevel> mips;
-};
-
-class DDSFile
-{
-public:
- bool loadFromFile(const QString& path);
- bool loadFromData(const QByteArray& data);
-
- uint32_t width() const { return m_width; }
- uint32_t height() const { return m_height; }
- bool isCubemap() const { return m_cubemap; }
- int faceCount() const { return m_faces.size(); }
- int mipCount() const { return m_faces.isEmpty() ? 0 : m_faces[0].mips.size(); }
- const DDSFace& face(int i) const { return m_faces[i]; }
- const GLFormatInfo& glFormat() const { return m_glFormat; }
- QString description() const { return m_description; }
-
-private:
- bool parse(const QByteArray& data);
-
- uint32_t m_width = 0;
- uint32_t m_height = 0;
- bool m_cubemap = false;
- GLFormatInfo m_glFormat;
- DXGIFormat m_dxgiFormat = DXGIFormat::UNKNOWN;
- QString m_description;
- QVector<DDSFace> m_faces;
-};
-
-#endif // DDSFILE_H
diff --git a/libs/preview_dds_native/src/ddsformat.cpp b/libs/preview_dds_native/src/ddsformat.cpp
deleted file mode 100644
index b56db91..0000000
--- a/libs/preview_dds_native/src/ddsformat.cpp
+++ /dev/null
@@ -1,619 +0,0 @@
-#include "ddsformat.h"
-
-#include <QOpenGLFunctions>
-#include <QString>
-
-#include <algorithm>
-#include <cstring>
-
-// GL compressed format constants not always in headers
-#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
-#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
-#endif
-#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
-#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
-#endif
-#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
-#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
-#endif
-#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
-#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
-#endif
-#ifndef GL_COMPRESSED_RED_RGTC1
-#define GL_COMPRESSED_RED_RGTC1 0x8DBB
-#endif
-#ifndef GL_COMPRESSED_SIGNED_RED_RGTC1
-#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
-#endif
-#ifndef GL_COMPRESSED_RG_RGTC2
-#define GL_COMPRESSED_RG_RGTC2 0x8DBD
-#endif
-#ifndef GL_COMPRESSED_SIGNED_RG_RGTC2
-#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
-#endif
-#ifndef GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
-#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
-#endif
-#ifndef GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT
-#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
-#endif
-#ifndef GL_COMPRESSED_RGBA_BPTC_UNORM
-#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
-#endif
-#ifndef GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM
-#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
-#endif
-#ifndef GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
-#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C
-#endif
-#ifndef GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
-#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
-#endif
-#ifndef GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
-#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
-#endif
-#ifndef GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
-#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
-#endif
-
-static GLFormatInfo dxgiToGL(DXGIFormat fmt)
-{
- GLFormatInfo info;
- info.valid = true;
-
- switch (fmt) {
- // BC1 (DXT1)
- case DXGIFormat::BC1_UNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- break;
- case DXGIFormat::BC1_UNORM_SRGB:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
- break;
- // BC2 (DXT3)
- case DXGIFormat::BC2_UNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- break;
- case DXGIFormat::BC2_UNORM_SRGB:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
- break;
- // BC3 (DXT5)
- case DXGIFormat::BC3_UNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- break;
- case DXGIFormat::BC3_UNORM_SRGB:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
- break;
- // BC4
- case DXGIFormat::BC4_UNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RED_RGTC1;
- break;
- case DXGIFormat::BC4_SNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_SIGNED_RED_RGTC1;
- break;
- // BC5
- case DXGIFormat::BC5_UNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RG_RGTC2;
- break;
- case DXGIFormat::BC5_SNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_SIGNED_RG_RGTC2;
- break;
- // BC6H
- case DXGIFormat::BC6H_UF16:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
- break;
- case DXGIFormat::BC6H_SF16:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
- break;
- // BC7
- case DXGIFormat::BC7_UNORM:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM;
- break;
- case DXGIFormat::BC7_UNORM_SRGB:
- info.compressed = true;
- info.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
- break;
-
- // Uncompressed RGBA
- case DXGIFormat::R8G8B8A8_UNORM:
- case DXGIFormat::R8G8B8A8_UNORM_SRGB:
- info.internalFormat = GL_RGBA8;
- info.format = GL_RGBA;
- info.type = GL_UNSIGNED_BYTE;
- break;
- case DXGIFormat::R8G8B8A8_UINT:
- info.internalFormat = GL_RGBA8UI;
- info.format = GL_RGBA_INTEGER;
- info.type = GL_UNSIGNED_BYTE;
- info.sampler = SamplerType::UInt;
- break;
- case DXGIFormat::R8G8B8A8_SNORM:
- info.internalFormat = GL_RGBA8_SNORM;
- info.format = GL_RGBA;
- info.type = GL_BYTE;
- break;
- case DXGIFormat::R8G8B8A8_SINT:
- info.internalFormat = GL_RGBA8I;
- info.format = GL_RGBA_INTEGER;
- info.type = GL_BYTE;
- info.sampler = SamplerType::SInt;
- break;
-
- // BGRA
- case DXGIFormat::B8G8R8A8_UNORM:
- case DXGIFormat::B8G8R8A8_UNORM_SRGB:
- info.internalFormat = GL_RGBA8;
- info.format = GL_BGRA;
- info.type = GL_UNSIGNED_BYTE;
- break;
- case DXGIFormat::B8G8R8X8_UNORM:
- case DXGIFormat::B8G8R8X8_UNORM_SRGB:
- info.internalFormat = GL_RGBA8;
- info.format = GL_BGRA;
- info.type = GL_UNSIGNED_BYTE;
- break;
-
- // 16-bit float
- case DXGIFormat::R16G16B16A16_FLOAT:
- info.internalFormat = GL_RGBA16F;
- info.format = GL_RGBA;
- info.type = GL_HALF_FLOAT;
- break;
- case DXGIFormat::R16G16B16A16_UNORM:
- info.internalFormat = GL_RGBA16;
- info.format = GL_RGBA;
- info.type = GL_UNSIGNED_SHORT;
- break;
- case DXGIFormat::R16G16B16A16_UINT:
- info.internalFormat = GL_RGBA16UI;
- info.format = GL_RGBA_INTEGER;
- info.type = GL_UNSIGNED_SHORT;
- info.sampler = SamplerType::UInt;
- break;
- case DXGIFormat::R16G16B16A16_SNORM:
- info.internalFormat = GL_RGBA16_SNORM;
- info.format = GL_RGBA;
- info.type = GL_SHORT;
- break;
- case DXGIFormat::R16G16B16A16_SINT:
- info.internalFormat = GL_RGBA16I;
- info.format = GL_RGBA_INTEGER;
- info.type = GL_SHORT;
- info.sampler = SamplerType::SInt;
- break;
-
- // 32-bit float
- case DXGIFormat::R32G32B32A32_FLOAT:
- info.internalFormat = GL_RGBA32F;
- info.format = GL_RGBA;
- info.type = GL_FLOAT;
- break;
- case DXGIFormat::R32G32B32_FLOAT:
- info.internalFormat = GL_RGB32F;
- info.format = GL_RGB;
- info.type = GL_FLOAT;
- break;
-
- // RG formats
- case DXGIFormat::R8G8_UNORM:
- info.internalFormat = GL_RG8;
- info.format = GL_RG;
- info.type = GL_UNSIGNED_BYTE;
- break;
- case DXGIFormat::R16G16_FLOAT:
- info.internalFormat = GL_RG16F;
- info.format = GL_RG;
- info.type = GL_HALF_FLOAT;
- break;
- case DXGIFormat::R16G16_UNORM:
- info.internalFormat = GL_RG16;
- info.format = GL_RG;
- info.type = GL_UNSIGNED_SHORT;
- break;
- case DXGIFormat::R32G32_FLOAT:
- info.internalFormat = GL_RG32F;
- info.format = GL_RG;
- info.type = GL_FLOAT;
- break;
-
- // R formats
- case DXGIFormat::R8_UNORM:
- info.internalFormat = GL_R8;
- info.format = GL_RED;
- info.type = GL_UNSIGNED_BYTE;
- break;
- case DXGIFormat::R16_FLOAT:
- info.internalFormat = GL_R16F;
- info.format = GL_RED;
- info.type = GL_HALF_FLOAT;
- break;
- case DXGIFormat::R16_UNORM:
- info.internalFormat = GL_R16;
- info.format = GL_RED;
- info.type = GL_UNSIGNED_SHORT;
- break;
- case DXGIFormat::R32_FLOAT:
- info.internalFormat = GL_R32F;
- info.format = GL_RED;
- info.type = GL_FLOAT;
- break;
- case DXGIFormat::A8_UNORM:
- info.internalFormat = GL_R8;
- info.format = GL_RED;
- info.type = GL_UNSIGNED_BYTE;
- break;
-
- // Packed formats
- case DXGIFormat::R10G10B10A2_UNORM:
- info.internalFormat = GL_RGB10_A2;
- info.format = GL_RGBA;
- info.type = GL_UNSIGNED_INT_2_10_10_10_REV;
- break;
- case DXGIFormat::R11G11B10_FLOAT:
- info.internalFormat = GL_R11F_G11F_B10F;
- info.format = GL_RGB;
- info.type = GL_UNSIGNED_INT_10F_11F_11F_REV;
- break;
- case DXGIFormat::B5G6R5_UNORM:
- info.internalFormat = GL_RGB565;
- info.format = GL_RGB;
- info.type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case DXGIFormat::B5G5R5A1_UNORM:
- info.internalFormat = GL_RGB5_A1;
- info.format = GL_BGRA;
- info.type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
- break;
- case DXGIFormat::B4G4R4A4_UNORM:
- info.internalFormat = GL_RGBA4;
- info.format = GL_BGRA;
- info.type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
- break;
-
- default:
- info.valid = false;
- break;
- }
-
- return info;
-}
-
-DXGIFormat fourCCToDXGI(uint32_t fourCC)
-{
- if (fourCC == makeFourCC('D', 'X', 'T', '1'))
- return DXGIFormat::BC1_UNORM;
- if (fourCC == makeFourCC('D', 'X', 'T', '3'))
- return DXGIFormat::BC2_UNORM;
- if (fourCC == makeFourCC('D', 'X', 'T', '5'))
- return DXGIFormat::BC3_UNORM;
- if (fourCC == makeFourCC('B', 'C', '4', 'U') ||
- fourCC == makeFourCC('A', 'T', 'I', '1'))
- return DXGIFormat::BC4_UNORM;
- if (fourCC == makeFourCC('B', 'C', '4', 'S'))
- return DXGIFormat::BC4_SNORM;
- if (fourCC == makeFourCC('A', 'T', 'I', '2') ||
- fourCC == makeFourCC('B', 'C', '5', 'U'))
- return DXGIFormat::BC5_UNORM;
- if (fourCC == makeFourCC('B', 'C', '5', 'S'))
- return DXGIFormat::BC5_SNORM;
-
- // Numeric FourCC codes for float/half-float formats
- switch (fourCC) {
- case 36:
- return DXGIFormat::R16G16B16A16_UNORM;
- case 110:
- return DXGIFormat::R16G16B16A16_SNORM;
- case 111:
- return DXGIFormat::R16_FLOAT;
- case 112:
- return DXGIFormat::R16G16_FLOAT;
- case 113:
- return DXGIFormat::R16G16B16A16_FLOAT;
- case 114:
- return DXGIFormat::R32_FLOAT;
- case 115:
- return DXGIFormat::R32G32_FLOAT;
- case 116:
- return DXGIFormat::R32G32B32A32_FLOAT;
- default:
- return DXGIFormat::UNKNOWN;
- }
-}
-
-// Helper: count trailing zeros / bit shift for a mask
-static int maskShift(uint32_t mask)
-{
- if (mask == 0)
- return 0;
- int shift = 0;
- while ((mask & 1) == 0) {
- mask >>= 1;
- ++shift;
- }
- return shift;
-}
-
-static int maskBits(uint32_t mask)
-{
- int count = 0;
- while (mask) {
- count += mask & 1;
- mask >>= 1;
- }
- return count;
-}
-
-// Build a converter for arbitrary bitmask pixel formats
-static GLFormatInfo buildBitmaskFormat(const DDSPixelFormat& pf)
-{
- GLFormatInfo info;
- info.valid = true;
-
- int rShift = maskShift(pf.dwRBitMask);
- int gShift = maskShift(pf.dwGBitMask);
- int bShift = maskShift(pf.dwBBitMask);
- int aShift = maskShift(pf.dwABitMask);
- int rBits = maskBits(pf.dwRBitMask);
- int gBits = maskBits(pf.dwGBitMask);
- int bBits = maskBits(pf.dwBBitMask);
- int aBits = maskBits(pf.dwABitMask);
- int bpp = pf.dwRGBBitCount;
-
- // Try to match common uncompressed formats directly
- if (bpp == 32 && pf.dwRBitMask == 0x000000FF && pf.dwGBitMask == 0x0000FF00 &&
- pf.dwBBitMask == 0x00FF0000 &&
- (pf.dwABitMask == 0xFF000000 || pf.dwABitMask == 0)) {
- info.internalFormat = GL_RGBA8;
- info.format = GL_RGBA;
- info.type = GL_UNSIGNED_BYTE;
- return info;
- }
- if (bpp == 32 && pf.dwRBitMask == 0x00FF0000 && pf.dwGBitMask == 0x0000FF00 &&
- pf.dwBBitMask == 0x000000FF) {
- info.internalFormat = GL_RGBA8;
- info.format = GL_BGRA;
- info.type = GL_UNSIGNED_BYTE;
- return info;
- }
-
- // Generic converter: extract channels and pack into RGBA8
- uint32_t rMask = pf.dwRBitMask;
- uint32_t gMask = pf.dwGBitMask;
- uint32_t bMask = pf.dwBBitMask;
- uint32_t aMask = pf.dwABitMask;
- bool hasAlpha = (pf.dwFlags & DDPF_ALPHAPIXELS) && aMask != 0;
- int bytesPerPixel = bpp / 8;
-
- info.internalFormat = GL_RGBA8;
- info.format = GL_RGBA;
- info.type = GL_UNSIGNED_BYTE;
- info.converter = [=](const QByteArray& data, int w, int h) -> QByteArray {
- QByteArray result(w * h * 4, '\0');
- const uint8_t* src = reinterpret_cast<const uint8_t*>(data.constData());
- uint8_t* dst = reinterpret_cast<uint8_t*>(result.data());
-
- for (int i = 0; i < w * h; ++i) {
- uint32_t pixel = 0;
- std::memcpy(&pixel, src + i * bytesPerPixel,
- std::min(bytesPerPixel, 4));
-
- int r = rBits > 0 ? ((pixel & rMask) >> rShift) * 255 / ((1 << rBits) - 1) : 0;
- int g = gBits > 0 ? ((pixel & gMask) >> gShift) * 255 / ((1 << gBits) - 1) : 0;
- int b = bBits > 0 ? ((pixel & bMask) >> bShift) * 255 / ((1 << bBits) - 1) : 0;
- int a = hasAlpha && aBits > 0
- ? ((pixel & aMask) >> aShift) * 255 / ((1 << aBits) - 1)
- : 255;
-
- dst[i * 4 + 0] = static_cast<uint8_t>(r);
- dst[i * 4 + 1] = static_cast<uint8_t>(g);
- dst[i * 4 + 2] = static_cast<uint8_t>(b);
- dst[i * 4 + 3] = static_cast<uint8_t>(a);
- }
- return result;
- };
-
- return info;
-}
-
-GLFormatInfo getGLFormat(const DDSPixelFormat& pf, const DDSHeaderDXT10* dxt10)
-{
- // DX10 extended header takes priority
- if (dxt10) {
- return dxgiToGL(dxt10->dxgiFormat);
- }
-
- // FourCC compressed or float formats
- if (pf.dwFlags & DDPF_FOURCC) {
- DXGIFormat dxgi = fourCCToDXGI(pf.dwFourCC);
- if (dxgi != DXGIFormat::UNKNOWN) {
- return dxgiToGL(dxgi);
- }
- GLFormatInfo info;
- info.valid = false;
- return info;
- }
-
- // Uncompressed with bitmasks
- if (pf.dwFlags & (DDPF_RGB | DDPF_LUMINANCE | DDPF_YUV | DDPF_ALPHA)) {
- return buildBitmaskFormat(pf);
- }
-
- GLFormatInfo info;
- info.valid = false;
- return info;
-}
-
-static bool isBlockCompressed(DXGIFormat fmt)
-{
- switch (fmt) {
- case DXGIFormat::BC1_UNORM:
- case DXGIFormat::BC1_UNORM_SRGB:
- case DXGIFormat::BC2_UNORM:
- case DXGIFormat::BC2_UNORM_SRGB:
- case DXGIFormat::BC3_UNORM:
- case DXGIFormat::BC3_UNORM_SRGB:
- case DXGIFormat::BC4_UNORM:
- case DXGIFormat::BC4_SNORM:
- case DXGIFormat::BC5_UNORM:
- case DXGIFormat::BC5_SNORM:
- case DXGIFormat::BC6H_UF16:
- case DXGIFormat::BC6H_SF16:
- case DXGIFormat::BC7_UNORM:
- case DXGIFormat::BC7_UNORM_SRGB:
- return true;
- default:
- return false;
- }
-}
-
-static int blockSize(DXGIFormat fmt)
-{
- switch (fmt) {
- case DXGIFormat::BC1_UNORM:
- case DXGIFormat::BC1_UNORM_SRGB:
- case DXGIFormat::BC4_UNORM:
- case DXGIFormat::BC4_SNORM:
- return 8;
- default:
- return 16;
- }
-}
-
-uint32_t mipDataSize(DXGIFormat fmt, const DDSPixelFormat& pf,
- uint32_t width, uint32_t height)
-{
- if (isBlockCompressed(fmt)) {
- uint32_t blocksW = std::max(1u, (width + 3) / 4);
- uint32_t blocksH = std::max(1u, (height + 3) / 4);
- return blocksW * blocksH * blockSize(fmt);
- }
-
- // Uncompressed: use bits per pixel
- uint32_t bpp = pf.dwRGBBitCount;
- if (bpp == 0) {
- // Estimate from DXGI format for non-bitmask formats
- switch (fmt) {
- case DXGIFormat::R32G32B32A32_FLOAT:
- bpp = 128;
- break;
- case DXGIFormat::R32G32B32_FLOAT:
- bpp = 96;
- break;
- case DXGIFormat::R16G16B16A16_FLOAT:
- case DXGIFormat::R16G16B16A16_UNORM:
- case DXGIFormat::R16G16B16A16_SNORM:
- case DXGIFormat::R32G32_FLOAT:
- bpp = 64;
- break;
- case DXGIFormat::R8G8B8A8_UNORM:
- case DXGIFormat::R8G8B8A8_UNORM_SRGB:
- case DXGIFormat::B8G8R8A8_UNORM:
- case DXGIFormat::B8G8R8X8_UNORM:
- case DXGIFormat::R16G16_FLOAT:
- case DXGIFormat::R16G16_UNORM:
- case DXGIFormat::R32_FLOAT:
- case DXGIFormat::R10G10B10A2_UNORM:
- case DXGIFormat::R11G11B10_FLOAT:
- bpp = 32;
- break;
- case DXGIFormat::R8G8_UNORM:
- case DXGIFormat::R16_FLOAT:
- case DXGIFormat::R16_UNORM:
- case DXGIFormat::B5G6R5_UNORM:
- case DXGIFormat::B5G5R5A1_UNORM:
- case DXGIFormat::B4G4R4A4_UNORM:
- bpp = 16;
- break;
- case DXGIFormat::R8_UNORM:
- case DXGIFormat::A8_UNORM:
- bpp = 8;
- break;
- default:
- bpp = 32;
- break;
- }
- }
- return width * height * bpp / 8;
-}
-
-static const char* dxgiFormatName(DXGIFormat fmt)
-{
- switch (fmt) {
- case DXGIFormat::BC1_UNORM:
- return "BC1_UNORM (DXT1)";
- case DXGIFormat::BC1_UNORM_SRGB:
- return "BC1_UNORM_SRGB";
- case DXGIFormat::BC2_UNORM:
- return "BC2_UNORM (DXT3)";
- case DXGIFormat::BC2_UNORM_SRGB:
- return "BC2_UNORM_SRGB";
- case DXGIFormat::BC3_UNORM:
- return "BC3_UNORM (DXT5)";
- case DXGIFormat::BC3_UNORM_SRGB:
- return "BC3_UNORM_SRGB";
- case DXGIFormat::BC4_UNORM:
- return "BC4_UNORM";
- case DXGIFormat::BC4_SNORM:
- return "BC4_SNORM";
- case DXGIFormat::BC5_UNORM:
- return "BC5_UNORM";
- case DXGIFormat::BC5_SNORM:
- return "BC5_SNORM";
- case DXGIFormat::BC6H_UF16:
- return "BC6H_UF16";
- case DXGIFormat::BC6H_SF16:
- return "BC6H_SF16";
- case DXGIFormat::BC7_UNORM:
- return "BC7_UNORM";
- case DXGIFormat::BC7_UNORM_SRGB:
- return "BC7_UNORM_SRGB";
- case DXGIFormat::R8G8B8A8_UNORM:
- return "R8G8B8A8_UNORM";
- case DXGIFormat::R8G8B8A8_UNORM_SRGB:
- return "R8G8B8A8_UNORM_SRGB";
- case DXGIFormat::B8G8R8A8_UNORM:
- return "B8G8R8A8_UNORM";
- case DXGIFormat::R16G16B16A16_FLOAT:
- return "R16G16B16A16_FLOAT";
- case DXGIFormat::R32G32B32A32_FLOAT:
- return "R32G32B32A32_FLOAT";
- default:
- return "Unknown";
- }
-}
-
-QString formatDescription(const DDSPixelFormat& pf, const DDSHeaderDXT10* dxt10)
-{
- if (dxt10) {
- return QString("DXGI: %1").arg(dxgiFormatName(dxt10->dxgiFormat));
- }
-
- if (pf.dwFlags & DDPF_FOURCC) {
- char cc[5] = {0};
- std::memcpy(cc, &pf.dwFourCC, 4);
- DXGIFormat dxgi = fourCCToDXGI(pf.dwFourCC);
- if (dxgi != DXGIFormat::UNKNOWN) {
- return QString("FourCC: %1 (%2)").arg(cc).arg(dxgiFormatName(dxgi));
- }
- return QString("FourCC: %1").arg(cc);
- }
-
- return QString("%1-bit R:0x%2 G:0x%3 B:0x%4 A:0x%5")
- .arg(pf.dwRGBBitCount)
- .arg(pf.dwRBitMask, 0, 16)
- .arg(pf.dwGBitMask, 0, 16)
- .arg(pf.dwBBitMask, 0, 16)
- .arg(pf.dwABitMask, 0, 16);
-}
diff --git a/libs/preview_dds_native/src/ddsformat.h b/libs/preview_dds_native/src/ddsformat.h
deleted file mode 100644
index 22d3565..0000000
--- a/libs/preview_dds_native/src/ddsformat.h
+++ /dev/null
@@ -1,200 +0,0 @@
-#ifndef DDSFORMAT_H
-#define DDSFORMAT_H
-
-#include <cstdint>
-#include <functional>
-#include <vector>
-
-#include <QByteArray>
-
-// DDS file magic number
-constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
-
-// DDS_PIXELFORMAT flags
-constexpr uint32_t DDPF_ALPHAPIXELS = 0x1;
-constexpr uint32_t DDPF_ALPHA = 0x2;
-constexpr uint32_t DDPF_FOURCC = 0x4;
-constexpr uint32_t DDPF_RGB = 0x40;
-constexpr uint32_t DDPF_YUV = 0x200;
-constexpr uint32_t DDPF_LUMINANCE = 0x20000;
-
-// DDS_HEADER flags
-constexpr uint32_t DDSD_CAPS = 0x1;
-constexpr uint32_t DDSD_HEIGHT = 0x2;
-constexpr uint32_t DDSD_WIDTH = 0x4;
-constexpr uint32_t DDSD_PITCH = 0x8;
-constexpr uint32_t DDSD_PIXELFORMAT = 0x1000;
-constexpr uint32_t DDSD_MIPMAPCOUNT = 0x20000;
-constexpr uint32_t DDSD_LINEARSIZE = 0x80000;
-constexpr uint32_t DDSD_DEPTH = 0x800000;
-
-// DDS_HEADER caps2
-constexpr uint32_t DDSCAPS2_CUBEMAP = 0x200;
-constexpr uint32_t DDSCAPS2_CUBEMAP_POSITIVEX = 0x400;
-constexpr uint32_t DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800;
-constexpr uint32_t DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000;
-constexpr uint32_t DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000;
-constexpr uint32_t DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000;
-constexpr uint32_t DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000;
-constexpr uint32_t DDSCAPS2_VOLUME = 0x200000;
-
-constexpr uint32_t DDSCAPS2_CUBEMAP_ALLFACES =
- DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX |
- DDSCAPS2_CUBEMAP_POSITIVEY | DDSCAPS2_CUBEMAP_NEGATIVEY |
- DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ;
-
-// DXGI formats (subset covering common DDS textures)
-enum class DXGIFormat : uint32_t {
- UNKNOWN = 0,
- R32G32B32A32_FLOAT = 2,
- R32G32B32A32_UINT = 3,
- R32G32B32A32_SINT = 4,
- R32G32B32_FLOAT = 6,
- R32G32B32_UINT = 7,
- R32G32B32_SINT = 8,
- R16G16B16A16_FLOAT = 10,
- R16G16B16A16_UNORM = 11,
- R16G16B16A16_UINT = 12,
- R16G16B16A16_SNORM = 13,
- R16G16B16A16_SINT = 14,
- R32G32_FLOAT = 16,
- R32G32_UINT = 17,
- R32G32_SINT = 18,
- R10G10B10A2_UNORM = 24,
- R10G10B10A2_UINT = 25,
- R11G11B10_FLOAT = 26,
- R8G8B8A8_UNORM = 28,
- R8G8B8A8_UNORM_SRGB = 29,
- R8G8B8A8_UINT = 30,
- R8G8B8A8_SNORM = 31,
- R8G8B8A8_SINT = 32,
- R16G16_FLOAT = 34,
- R16G16_UNORM = 35,
- R16G16_UINT = 36,
- R16G16_SNORM = 37,
- R16G16_SINT = 38,
- R32_FLOAT = 41,
- R32_UINT = 42,
- R32_SINT = 43,
- R8G8_UNORM = 49,
- R8G8_UINT = 50,
- R8G8_SNORM = 51,
- R8G8_SINT = 52,
- R16_FLOAT = 54,
- R16_UNORM = 56,
- R16_UINT = 57,
- R16_SNORM = 58,
- R16_SINT = 59,
- R8_UNORM = 61,
- R8_UINT = 62,
- R8_SNORM = 63,
- R8_SINT = 64,
- A8_UNORM = 65,
- BC1_UNORM = 71,
- BC1_UNORM_SRGB = 72,
- BC2_UNORM = 74,
- BC2_UNORM_SRGB = 75,
- BC3_UNORM = 77,
- BC3_UNORM_SRGB = 78,
- BC4_UNORM = 80,
- BC4_SNORM = 81,
- BC5_UNORM = 83,
- BC5_SNORM = 84,
- B5G6R5_UNORM = 85,
- B5G5R5A1_UNORM = 86,
- B8G8R8A8_UNORM = 87,
- B8G8R8X8_UNORM = 88,
- B8G8R8A8_UNORM_SRGB = 91,
- B8G8R8X8_UNORM_SRGB = 93,
- BC6H_UF16 = 95,
- BC6H_SF16 = 96,
- BC7_UNORM = 98,
- BC7_UNORM_SRGB = 99,
- B4G4R4A4_UNORM = 115,
-};
-
-// D3D10 resource dimension
-enum class D3D10ResourceDimension : uint32_t {
- Unknown = 0,
- Buffer = 1,
- Texture1D = 2,
- Texture2D = 3,
- Texture3D = 4,
-};
-
-#pragma pack(push, 1)
-
-struct DDSPixelFormat {
- uint32_t dwSize;
- uint32_t dwFlags;
- uint32_t dwFourCC;
- uint32_t dwRGBBitCount;
- uint32_t dwRBitMask;
- uint32_t dwGBitMask;
- uint32_t dwBBitMask;
- uint32_t dwABitMask;
-};
-
-struct DDSHeader {
- uint32_t dwSize;
- uint32_t dwFlags;
- uint32_t dwHeight;
- uint32_t dwWidth;
- uint32_t dwPitchOrLinearSize;
- uint32_t dwDepth;
- uint32_t dwMipMapCount;
- uint32_t dwReserved1[11];
- DDSPixelFormat ddspf;
- uint32_t dwCaps;
- uint32_t dwCaps2;
- uint32_t dwCaps3;
- uint32_t dwCaps4;
- uint32_t dwReserved2;
-};
-
-struct DDSHeaderDXT10 {
- DXGIFormat dxgiFormat;
- D3D10ResourceDimension resourceDimension;
- uint32_t miscFlag;
- uint32_t arraySize;
- uint32_t miscFlags2;
-};
-
-#pragma pack(pop)
-
-// Sampler type for shader selection
-enum class SamplerType { Float, UInt, SInt };
-
-// OpenGL format info
-struct GLFormatInfo {
- bool valid = false;
- bool compressed = false;
- uint32_t internalFormat = 0;
- uint32_t format = 0; // only for uncompressed
- uint32_t type = 0; // only for uncompressed
- SamplerType sampler = SamplerType::Float;
- // Optional converter for non-standard bitmask formats
- std::function<QByteArray(const QByteArray&, int, int)> converter;
-};
-
-// Inline helper: make a FourCC from 4 chars
-constexpr uint32_t makeFourCC(char a, char b, char c, char d)
-{
- return static_cast<uint32_t>(a) | (static_cast<uint32_t>(b) << 8) |
- (static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24);
-}
-
-// Convert a FourCC code to DXGI format
-DXGIFormat fourCCToDXGI(uint32_t fourCC);
-
-// Resolve the OpenGL format from a DDS pixel format + optional DXT10 header
-GLFormatInfo getGLFormat(const DDSPixelFormat& pf, const DDSHeaderDXT10* dxt10);
-
-// Calculate mip level data size in bytes
-uint32_t mipDataSize(DXGIFormat fmt, const DDSPixelFormat& pf,
- uint32_t width, uint32_t height);
-
-// Get a human-readable format description
-QString formatDescription(const DDSPixelFormat& pf, const DDSHeaderDXT10* dxt10);
-
-#endif // DDSFORMAT_H
diff --git a/libs/preview_dds_native/src/ddspreview.cpp b/libs/preview_dds_native/src/ddspreview.cpp
deleted file mode 100644
index 2bb95be..0000000
--- a/libs/preview_dds_native/src/ddspreview.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-#include "ddspreview.h"
-#include "ddsfile.h"
-#include "ddswidget.h"
-
-#include <QLabel>
-#include <QVBoxLayout>
-#include <QWidget>
-
-using namespace MOBase;
-
-DDSPreview::DDSPreview() {}
-
-bool DDSPreview::init(IOrganizer* moInfo)
-{
- m_organizer = moInfo;
- return true;
-}
-
-QString DDSPreview::name() const
-{
- return "DDS Preview (Native)";
-}
-
-QString DDSPreview::localizedName() const
-{
- return tr("DDS Preview (Native)");
-}
-
-QString DDSPreview::author() const
-{
- return "AnyOldName3";
-}
-
-QString DDSPreview::description() const
-{
- return tr("Displays DDS texture files using OpenGL.");
-}
-
-VersionInfo DDSPreview::version() const
-{
- return VersionInfo(1, 0, 0, VersionInfo::RELEASE_FINAL);
-}
-
-QList<PluginSetting> DDSPreview::settings() const
-{
- return {};
-}
-
-std::set<QString> DDSPreview::supportedExtensions() const
-{
- return {"dds"};
-}
-
-bool DDSPreview::supportsArchives() const
-{
- return true;
-}
-
-QWidget* DDSPreview::genFilePreview(const QString& fileName,
- const QSize& maxSize) const
-{
- DDSFile dds;
- if (!dds.loadFromFile(fileName)) {
- QLabel* label = new QLabel(tr("Failed to load DDS file."));
- label->setAlignment(Qt::AlignCenter);
- return label;
- }
- return buildPreview(dds, maxSize);
-}
-
-QWidget* DDSPreview::genDataPreview(const QByteArray& fileData,
- const QString& fileName,
- const QSize& maxSize) const
-{
- DDSFile dds;
- if (!dds.loadFromData(fileData)) {
- QLabel* label = new QLabel(tr("Failed to load DDS data."));
- label->setAlignment(Qt::AlignCenter);
- return label;
- }
- return buildPreview(dds, maxSize);
-}
-
-QWidget* DDSPreview::buildPreview(DDSFile& dds, const QSize& maxSize) const
-{
- QWidget* container = new QWidget();
- QVBoxLayout* layout = new QVBoxLayout(container);
-
- // Description label
- QLabel* descLabel = new QLabel(dds.description());
- descLabel->setAlignment(Qt::AlignCenter);
- layout->addWidget(descLabel);
-
- // OpenGL preview widget — we need to keep the DDSFile alive, so store
- // it in the container. We use a shared_ptr stored as a property.
- auto* ddsPtr = new DDSFile(std::move(dds));
- DDSWidget* widget = new DDSWidget(*ddsPtr, container);
-
- // Clean up DDSFile when container is destroyed
- QObject::connect(container, &QObject::destroyed, [ddsPtr]() {
- delete ddsPtr;
- });
-
- // Size the widget proportionally
- int previewW = maxSize.width();
- int previewH = maxSize.height() - 30; // leave room for label
- if (ddsPtr->width() > 0 && ddsPtr->height() > 0) {
- float texAspect =
- static_cast<float>(ddsPtr->width()) / ddsPtr->height();
- float availAspect =
- static_cast<float>(previewW) / std::max(1, previewH);
- if (texAspect > availAspect) {
- previewH = static_cast<int>(previewW / texAspect);
- } else {
- previewW = static_cast<int>(previewH * texAspect);
- }
- }
- widget->setMinimumSize(std::min(previewW, static_cast<int>(ddsPtr->width())),
- std::min(previewH, static_cast<int>(ddsPtr->height())));
- widget->setMaximumSize(previewW, previewH);
-
- layout->addWidget(widget);
- container->setLayout(layout);
-
- return container;
-}
diff --git a/libs/preview_dds_native/src/ddspreview.h b/libs/preview_dds_native/src/ddspreview.h
deleted file mode 100644
index 36f2bec..0000000
--- a/libs/preview_dds_native/src/ddspreview.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef DDSPREVIEW_H
-#define DDSPREVIEW_H
-
-#include <set>
-
-#include <QString>
-
-#include <uibase/iplugin.h>
-#include <uibase/ipluginpreview.h>
-
-class DDSPreview : public MOBase::IPluginPreview
-{
- Q_OBJECT
- Q_INTERFACES(MOBase::IPlugin MOBase::IPluginPreview)
- Q_PLUGIN_METADATA(IID "org.tannin.DDSPreviewNative")
-
-public:
- DDSPreview();
-
-public: // IPlugin
- bool init(MOBase::IOrganizer* moInfo) override;
- QString name() const override;
- QString localizedName() const override;
- QString author() const override;
- QString description() const override;
- MOBase::VersionInfo version() const override;
- QList<MOBase::PluginSetting> settings() const override;
-
-public: // IPluginPreview
- std::set<QString> supportedExtensions() const override;
- QWidget* genFilePreview(const QString& fileName,
- const QSize& maxSize) const override;
- bool supportsArchives() const override;
- QWidget* genDataPreview(const QByteArray& fileData,
- const QString& fileName,
- const QSize& maxSize) const override;
-
-private:
- QWidget* buildPreview(class DDSFile& dds, const QSize& maxSize) const;
-
- MOBase::IOrganizer* m_organizer = nullptr;
-};
-
-#endif // DDSPREVIEW_H
diff --git a/libs/preview_dds_native/src/ddswidget.cpp b/libs/preview_dds_native/src/ddswidget.cpp
deleted file mode 100644
index 43eb586..0000000
--- a/libs/preview_dds_native/src/ddswidget.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-#include "ddswidget.h"
-
-#include <QDebug>
-
-#include <algorithm>
-#include <cstring>
-
-// Vertex data: position (x,y) + texcoord (u,v)
-static const float quadVertices[] = {
- // pos // tex
- -1.0f, -1.0f, 0.0f, 1.0f,
- 1.0f, -1.0f, 1.0f, 1.0f,
- -1.0f, 1.0f, 0.0f, 0.0f,
- 1.0f, 1.0f, 1.0f, 0.0f,
-};
-
-static const char* vertexShaderSrc = R"(
-#version 330 core
-layout(location = 0) in vec2 aPos;
-layout(location = 1) in vec2 aTexCoord;
-out vec2 vTexCoord;
-uniform float uAspect;
-uniform float uWidgetAspect;
-void main() {
- vec2 pos = aPos;
- float ratio = uAspect / uWidgetAspect;
- if (ratio > 1.0)
- pos.y *= 1.0 / ratio;
- else
- pos.x *= ratio;
- gl_Position = vec4(pos, 0.0, 1.0);
- vTexCoord = aTexCoord;
-}
-)";
-
-static const char* fragmentShaderSrc = R"(
-#version 330 core
-in vec2 vTexCoord;
-out vec4 fragColor;
-uniform sampler2D uTexture;
-void main() {
- vec4 texel = texture(uTexture, vTexCoord);
- // Checkerboard for transparency
- vec2 checker = floor(vTexCoord * 16.0);
- float c = mod(checker.x + checker.y, 2.0);
- vec3 bg = mix(vec3(0.6), vec3(0.4), c);
- fragColor = vec4(mix(bg, texel.rgb, texel.a), 1.0);
-}
-)";
-
-static const char* cubemapFragSrc = R"(
-#version 330 core
-in vec2 vTexCoord;
-out vec4 fragColor;
-uniform samplerCube uTexture;
-void main() {
- // Spherical projection for cubemap preview
- float theta = vTexCoord.x * 6.28318530718;
- float phi = vTexCoord.y * 3.14159265359;
- vec3 dir = vec3(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta));
- vec4 texel = texture(uTexture, dir);
- vec2 checker = floor(vTexCoord * 16.0);
- float c = mod(checker.x + checker.y, 2.0);
- vec3 bg = mix(vec3(0.6), vec3(0.4), c);
- fragColor = vec4(mix(bg, texel.rgb, texel.a), 1.0);
-}
-)";
-
-DDSWidget::DDSWidget(const DDSFile& dds, QWidget* parent)
- : QOpenGLWidget(parent), m_dds(dds), m_vbo(QOpenGLBuffer::VertexBuffer)
-{
- if (dds.height() > 0) {
- m_aspectRatio =
- static_cast<float>(dds.width()) / static_cast<float>(dds.height());
- }
-}
-
-DDSWidget::~DDSWidget()
-{
- makeCurrent();
- delete m_texture;
- delete m_shader;
- m_vbo.destroy();
- doneCurrent();
-}
-
-void DDSWidget::initializeGL()
-{
- initializeOpenGLFunctions();
-
- glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
-
- // VBO
- m_vbo.create();
- m_vbo.bind();
- m_vbo.allocate(quadVertices, sizeof(quadVertices));
-
- setupShaders();
- uploadTexture();
-}
-
-void DDSWidget::setupShaders()
-{
- m_shader = new QOpenGLShaderProgram(this);
- m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSrc);
-
- if (m_dds.isCubemap()) {
- m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, cubemapFragSrc);
- } else {
- m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSrc);
- }
-
- m_shader->link();
-}
-
-void DDSWidget::uploadTexture()
-{
- if (m_dds.faceCount() == 0 || m_dds.mipCount() == 0)
- return;
-
- const auto& fmt = m_dds.glFormat();
-
- if (m_dds.isCubemap()) {
- m_texture = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
- } else {
- m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
- }
-
- m_texture->setAutoMipMapGenerationEnabled(false);
- m_texture->setMipLevels(m_dds.mipCount());
-
- if (m_dds.isCubemap()) {
- m_texture->setSize(m_dds.width(), m_dds.height());
- // Set format for allocation
- if (fmt.compressed) {
- m_texture->setFormat(
- static_cast<QOpenGLTexture::TextureFormat>(fmt.internalFormat));
- } else {
- m_texture->setFormat(
- static_cast<QOpenGLTexture::TextureFormat>(fmt.internalFormat));
- }
- m_texture->allocateStorage();
-
- static const QOpenGLTexture::CubeMapFace cubeMapFaces[] = {
- QOpenGLTexture::CubeMapPositiveX, QOpenGLTexture::CubeMapNegativeX,
- QOpenGLTexture::CubeMapPositiveY, QOpenGLTexture::CubeMapNegativeY,
- QOpenGLTexture::CubeMapPositiveZ, QOpenGLTexture::CubeMapNegativeZ,
- };
-
- int numFaces = std::min(m_dds.faceCount(), 6);
- for (int f = 0; f < numFaces; ++f) {
- const auto& face = m_dds.face(f);
- for (int m = 0; m < face.mips.size(); ++m) {
- const auto& mip = face.mips[m];
- QByteArray pixelData = mip.data;
- if (fmt.converter) {
- pixelData = fmt.converter(mip.data, mip.width, mip.height);
- }
- if (fmt.compressed) {
- m_texture->setCompressedData(
- m, 0, cubeMapFaces[f],
- pixelData.size(),
- pixelData.constData());
- } else {
- m_texture->setData(
- m, 0, cubeMapFaces[f],
- static_cast<QOpenGLTexture::PixelFormat>(fmt.format),
- static_cast<QOpenGLTexture::PixelType>(fmt.type),
- pixelData.constData());
- }
- }
- }
- } else {
- m_texture->setSize(m_dds.width(), m_dds.height());
- if (fmt.compressed) {
- m_texture->setFormat(
- static_cast<QOpenGLTexture::TextureFormat>(fmt.internalFormat));
- } else {
- m_texture->setFormat(
- static_cast<QOpenGLTexture::TextureFormat>(fmt.internalFormat));
- }
- m_texture->allocateStorage();
-
- const auto& face = m_dds.face(0);
- for (int m = 0; m < face.mips.size(); ++m) {
- const auto& mip = face.mips[m];
- QByteArray pixelData = mip.data;
- if (fmt.converter) {
- pixelData = fmt.converter(mip.data, mip.width, mip.height);
- }
- if (fmt.compressed) {
- m_texture->setCompressedData(
- m, 0,
- pixelData.size(),
- pixelData.constData());
- } else {
- m_texture->setData(
- m, 0,
- static_cast<QOpenGLTexture::PixelFormat>(fmt.format),
- static_cast<QOpenGLTexture::PixelType>(fmt.type),
- pixelData.constData());
- }
- }
- }
-
- m_texture->setWrapMode(QOpenGLTexture::ClampToEdge);
- if (fmt.sampler != SamplerType::Float) {
- m_texture->setMinMagFilters(QOpenGLTexture::Nearest,
- QOpenGLTexture::Nearest);
- } else {
- m_texture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,
- QOpenGLTexture::Linear);
- }
-}
-
-void DDSWidget::resizeGL(int w, int h)
-{
- glViewport(0, 0, w, h);
-}
-
-void DDSWidget::paintGL()
-{
- glClear(GL_COLOR_BUFFER_BIT);
-
- if (!m_texture || !m_shader)
- return;
-
- m_shader->bind();
- m_texture->bind();
-
- float widgetAspect = width() > 0 && height() > 0
- ? static_cast<float>(width()) / height()
- : 1.0f;
- m_shader->setUniformValue("uAspect", m_aspectRatio);
- m_shader->setUniformValue("uWidgetAspect", widgetAspect);
- m_shader->setUniformValue("uTexture", 0);
-
- m_vbo.bind();
- m_shader->enableAttributeArray(0);
- m_shader->enableAttributeArray(1);
- m_shader->setAttributeBuffer(0, GL_FLOAT, 0, 2, 4 * sizeof(float));
- m_shader->setAttributeBuffer(1, GL_FLOAT, 2 * sizeof(float), 2,
- 4 * sizeof(float));
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- m_shader->disableAttributeArray(0);
- m_shader->disableAttributeArray(1);
- m_vbo.release();
- m_texture->release();
- m_shader->release();
-}
diff --git a/libs/preview_dds_native/src/ddswidget.h b/libs/preview_dds_native/src/ddswidget.h
deleted file mode 100644
index 968e253..0000000
--- a/libs/preview_dds_native/src/ddswidget.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef DDSWIDGET_H
-#define DDSWIDGET_H
-
-#include "ddsfile.h"
-
-#include <QOpenGLBuffer>
-#include <QOpenGLFunctions>
-#include <QOpenGLShaderProgram>
-#include <QOpenGLTexture>
-#include <QOpenGLWidget>
-
-class DDSWidget : public QOpenGLWidget, protected QOpenGLFunctions
-{
- Q_OBJECT
-
-public:
- explicit DDSWidget(const DDSFile& dds, QWidget* parent = nullptr);
- ~DDSWidget() override;
-
-protected:
- void initializeGL() override;
- void resizeGL(int w, int h) override;
- void paintGL() override;
-
-private:
- void uploadTexture();
- void setupShaders();
-
- const DDSFile& m_dds;
- QOpenGLTexture* m_texture = nullptr;
- QOpenGLShaderProgram* m_shader = nullptr;
- QOpenGLBuffer m_vbo;
- float m_aspectRatio = 1.0f;
-};
-
-#endif // DDSWIDGET_H