Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
[submodule "lib/bcdec"]
path = lib/bcdec
url = https://github.com/iOrange/bcdec.git
url = https://github.com/neptuwunium/bcdec.git
[submodule "lib/Binary-Reader"]
path = lib/Binary-Reader
url = https://github.com/Puxtril/Binary-Reader.git
[submodule "lib/astc"]
path = lib/astc
url = https://github.com/ARM-software/astc-encoder
[submodule "lib/etc"]
path = lib/etc
url = https://github.com/Ericsson/ETCPACK/
41 changes: 34 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,60 @@ elseif(UNIX)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -ggdb")
endif()

option(TEXVIEWER_ASTC "Enable ASTC Decompression" ON)
option(TEXVIEWER_BPTC "Enable S3TC, RGTC and BPTC Decompression (BC1..7)" ON)
option(TEXVIEWER_ETC "Enable ETC Decompression" ON)
option(USE_SYSTEM_BCDEC "Use system bcdec instead of vendored" OFF)

add_subdirectory(lib)

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/Meta.h.in ${CMAKE_CURRENT_BINARY_DIR}/configured/Meta.h)

file(GLOB TEX_VIEWER_SOURCES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/src/*
${CMAKE_CURRENT_SOURCE_DIR}/include/MainWindow.h
${CMAKE_CURRENT_SOURCE_DIR}/include/ImageViewer.h
)

if (NOT TEXVIEWER_BPTC)
list(REMOVE_ITEM TEX_VIEWER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/ConverterBPTC.cpp)
endif()

if (NOT TEXVIEWER_ASTC)
list(REMOVE_ITEM TEX_VIEWER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/ConverterASTC.cpp)
endif()

if (NOT TEXVIEWER_ETC)
list(REMOVE_ITEM TEX_VIEWER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/ConverterETC.cpp)
endif()

set(GLOB TEX_VIEWER_SOURCES_UI CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/ui/MainWindow.ui
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/configured
${CMAKE_CURRENT_SOURCE_DIR}/lib/bcdec
${CMAKE_CURRENT_SOURCE_DIR}/lib/Binary-Reader/include
)

# Qt stuff
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/ui)

add_executable(TexViewer ${TEX_VIEWER_SOURCES} ${TEX_VIEWER_SOURCES_UI})
target_include_directories(TexViewer PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/configured
${CMAKE_CURRENT_SOURCE_DIR}/lib/Binary-Reader/include
)

if (NOT USE_SYSTEM_BCDEC)
target_include_directories(TexViewer PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib/bcdec)
endif()

find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
target_link_libraries(TexViewer Qt6::Core Qt6::Gui Qt6::Widgets)

if (TEXVIEWER_ASTC)
target_link_libraries(TexViewer ${ASTC_TARGET})
endif()

# Application will launch CMD window if this isn't set
if (MSVC)
target_link_options(TexViewer PUBLIC /SUBSYSTEM:windows /ENTRY:mainCRTStartup)
Expand All @@ -49,4 +76,4 @@ install(
TARGETS TexViewer
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
)
159 changes: 125 additions & 34 deletions include/ConverterBlockCompressed.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,56 @@
#include <QtGui/QImage>

#include <map>
#include "Meta.h"

#include "bcdec.h"
struct ImageData;

#define MAKE_SPEC(name) void name(const void*, void*, int)

// Used in BCDEC to define block decode functions
typedef void(*decodeFunc)(const void*, void*, int);
#ifdef TEXVIEWER_BPTC
#define BCDECDEF inline
#define BCDEC_BC4BC5_PRECISE
#define BCDEC_BC3_PRECISE
#include "bcdec.h"

// Specializations of bcdec's block decode functions
void bcdec_bc6hu(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
void bcdec_bc6hs(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
void _bcdec_bc6h_as_RGBA(const void* compressedBlock, void* decompressedBlock, int destinationPitch, bool isSigned);
void bcdec_bc5_as_RGB(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
MAKE_SPEC(bcdec_bc4u);
MAKE_SPEC(bcdec_bc5u);
MAKE_SPEC(bcdec_bc6hu);
MAKE_SPEC(bcdec_bc6hs);
#endif

#ifdef TEXVIEWER_ASTC
int convertAstc(char* inData, size_t inDataLen, char* outData, size_t outDataLen, int width, int height, const ImageData &info);
#endif

#ifdef TEXVIEWER_ETC
MAKE_SPEC(etcpack_etc1);
MAKE_SPEC(etcpack_etc2);
MAKE_SPEC(etcpack_etc2a1);
MAKE_SPEC(etcpack_etc2a8);
MAKE_SPEC(etcpack_eac1);
MAKE_SPEC(etcpack_eac2);
#endif

#undef MAKE_SPEC

typedef void (*decodeBlockFunc)(const void*, void*, int);
typedef int (*decodeFunc)(char*, size_t, char*, size_t, int, int, const ImageData &info);

struct ImageData
{
int blockSize;
int blockWidth;
int blockHeight;
int pitch; // bpp
decodeBlockFunc decodeBlock;
decodeFunc decode;
QImage::Format qFormat;
};

int getDecompressedSize(int srcBlockSize, int dstPixelSize, int width, int dataSize);
int convertBlocksSafe(const char* inData, size_t inDataLen, char* decompressed, int width, int srcBlockSize, int dstPixelSize, decodeFunc decodeFunc);
int getDecompressedHeight(const ImageData &info, int width, size_t dataSize);
int convertBlocksSafe(char* inData, size_t inDataLen, char* outData, size_t outDataLen, int width, int height, const ImageData &info);

enum ImageFormat
{
Expand All @@ -27,33 +63,88 @@ enum ImageFormat
BC5,
BC6HS,
BC6HU,
BC7
};
BC7,

struct ImageData
{
int blockSizeSrc;
int pixelSizeDst;
decodeFunc decode;
QImage::Format qFormat;
ASTC4x4,
ASTC5x4,
ASTC5x5,
ASTC6x5,
ASTC6x6,
ASTC8x5,
ASTC8x6,
ASTC8x8,
ASTC10x5,
ASTC10x6,
ASTC10x8,
ASTC10x10,
ASTC12x10,
ASTC12x12,

ETC1,
ETC2,
ETC2A1,
ETC2A8,
EAC1,
EAC2,
};

static constexpr ImageData BC1Data = {BCDEC_BC1_BLOCK_SIZE, 4, &bcdec_bc1, QImage::Format_RGBA8888 };
static constexpr ImageData BC2Data = {BCDEC_BC2_BLOCK_SIZE, 4, &bcdec_bc2, QImage::Format_RGBA8888 };
static constexpr ImageData BC3Data = {BCDEC_BC3_BLOCK_SIZE, 4, &bcdec_bc3, QImage::Format_RGBA8888 };
static constexpr ImageData BC4Data = {BCDEC_BC4_BLOCK_SIZE, 1, &bcdec_bc4, QImage::Format_Grayscale8};
static constexpr ImageData BC5Data = {BCDEC_BC5_BLOCK_SIZE, 3, &bcdec_bc5_as_RGB, QImage::Format_RGB888 };
static constexpr ImageData BC6HUData = {BCDEC_BC6H_BLOCK_SIZE, 16, &bcdec_bc6hu, QImage::Format_RGBX32FPx4};
static constexpr ImageData BC6HSData = {BCDEC_BC6H_BLOCK_SIZE, 16, &bcdec_bc6hs, QImage::Format_RGBX32FPx4};
static constexpr ImageData BC7Data = {BCDEC_BC7_BLOCK_SIZE, 4, &bcdec_bc7, QImage::Format_RGBA8888 };
#ifdef TEXVIEWER_BPTC
#define BPTC_DATA(blockSize, pitch, func, format) \
{ blockSize, 4, 4, pitch, &func, &convertBlocksSafe, QImage::format }
#else
#define BPTC_DATA(blockSize, pitch, func, format) \
{ blockSize, 4, 4, pitch, nullptr, nullptr, QImage::format }
#endif

#ifdef TEXVIEWER_ASTC
#define ASTC_DATA(blockSize, blockWidth, blockHeight) \
{ blockSize, blockWidth, blockHeight, 4, nullptr, &convertAstc, QImage::Format_RGBA8888 }
#else
#define ASTC_DATA(blockSize, blockWidth, blockHeight) \
{ blockSize, blockWidth, blockHeight, 4, nullptr, nullptr, QImage::Format_RGBA8888 }
#endif

#ifdef TEXVIEWER_ETC
#define ETC_DATA(blockSize, pitch, func, format) \
{ blockSize, 4, 4, pitch, &func, &convertBlocksSafe, QImage::format }
#else
#define ETC_DATA(blockSize, pitch, func, format) \
{ blockSize, 4, 4, pitch, nullptr, nullptr, QImage::format }
#endif

static const std::map<ImageFormat, ImageData> g_imageFormatData = {
{BC1, BC1Data},
{BC2, BC2Data},
{BC3, BC3Data},
{BC4, BC4Data},
{BC5, BC5Data},
{BC6HU, BC6HUData},
{BC6HS, BC6HSData},
{BC7, BC7Data}
};
{BC1, BPTC_DATA( 8, 4, bcdec_bc1, Format_RGBA8888)},
{BC2, BPTC_DATA(16, 4, bcdec_bc2, Format_RGBA8888)},
{BC3, BPTC_DATA(16, 4, bcdec_bc3, Format_RGBA8888)},
{BC4, BPTC_DATA( 8, 1, bcdec_bc4u, Format_Grayscale8)},
{BC5, BPTC_DATA(16, 3, bcdec_bc5u, Format_RGB888)},
{BC6HU, BPTC_DATA(16, 16, bcdec_bc6hu, Format_RGBX32FPx4)},
{BC6HS, BPTC_DATA(16, 16, bcdec_bc6hs, Format_RGBX32FPx4)},
{BC7, BPTC_DATA(16, 4, bcdec_bc7, Format_RGBA8888)},

{ ASTC4x4, ASTC_DATA(16, 4, 4) },
{ ASTC5x4, ASTC_DATA(16, 5, 4) },
{ ASTC5x5, ASTC_DATA(16, 5, 5) },
{ ASTC6x5, ASTC_DATA(16, 6, 5) },
{ ASTC6x6, ASTC_DATA(16, 6, 6) },
{ ASTC8x5, ASTC_DATA(16, 8, 5) },
{ ASTC8x6, ASTC_DATA(16, 8, 6) },
{ ASTC8x8, ASTC_DATA(16, 8, 8) },
{ ASTC10x5, ASTC_DATA(16, 10, 5) },
{ ASTC10x6, ASTC_DATA(16, 10, 6) },
{ ASTC10x8, ASTC_DATA(16, 10, 8) },
{ ASTC10x10, ASTC_DATA(16, 10, 10) },
{ ASTC12x10, ASTC_DATA(16, 12, 10) },
{ ASTC12x12, ASTC_DATA(16, 12, 12) },

{ETC1, ETC_DATA( 8, 3, etcpack_etc1, Format_RGB888)},
{ETC2, ETC_DATA( 8, 3, etcpack_etc2, Format_RGB888)},
{ETC2A1, ETC_DATA( 8, 4, etcpack_etc2a1, Format_RGBA8888)},
{ETC2A8, ETC_DATA(16, 4, etcpack_etc2a8, Format_RGBA8888)},
{EAC1, ETC_DATA( 8, 1, etcpack_eac1, Format_Grayscale8)},
{EAC2, ETC_DATA(16, 3, etcpack_eac2, Format_RGB888)},
};

#undef BPTC_DATA
#undef ASTC_DATA
#undef ETC_DATA
7 changes: 5 additions & 2 deletions include/ImageViewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@
#include "ConverterBlockCompressed.h"
#include "ConverterUncompressed.h"
#include "BinaryReaderSlice.h"
#include "ZoomableLabel.h"

class ImageViewer : public QObject
{
Q_OBJECT

QLabel* m_labelViewer;
ZoomableLabel* m_labelViewer;
QScrollArea* m_scrollArea;
bool m_isCompressed;

char* m_rawData;
size_t m_rawDataSize;
size_t m_rawDataOffset;
int m_width;
int m_height;
ImageFormat m_format;
UncompressedLayout m_uncompressedLayout;
QPixmap m_pixmap;
Expand All @@ -37,6 +39,7 @@ class ImageViewer : public QObject
void setIsCompressed(bool isCompressed);
void setImageData(char* data, size_t size);
void setWidth(int width);
void setHeight(int height);
void setFormat(ImageFormat format);
void setOffset(size_t dataOffset);
void setUncompressedStruct(UncompressedLayout layout);
Expand All @@ -48,4 +51,4 @@ class ImageViewer : public QObject

signals:
void errorMessage(const QString& msg, int timeout = 5000);
};
};
2 changes: 2 additions & 0 deletions include/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class MainWindow : public QObject, private Ui_MainWindow

QFileDialog m_dialog;
ImageViewer m_viewer;
QMainWindow* m_mainWindow;
std::vector<std::pair<QComboBox*, QSpinBox*>> m_uncompressedOptions;

public:
Expand All @@ -38,6 +39,7 @@ public slots:
void offsetComboChanged(int index);
void offsetInputChanged(int value);
void widthChanged(int value);
void heightChanged(int value);

// Uncompressed widgets
void channel0ComboChanged(int index);
Expand Down
4 changes: 4 additions & 0 deletions include/Meta.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
#else
#define TEXVIEWER_VERSION_STR "@TexViewer_VERSION_MAJOR@.@TexViewer_VERSION_MINOR@"
#endif

#cmakedefine TEXVIEWER_ASTC
#cmakedefine TEXVIEWER_BPTC
#cmakedefine TEXVIEWER_ETC
4 changes: 3 additions & 1 deletion include/Pow2Spinbox.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include <QtWidgets/qspinbox.h>
#include <QSpinBox>
#include <bit>
#include <QGuiApplication>

class Pow2Spinbox : public QSpinBox
{
Expand Down
26 changes: 26 additions & 0 deletions include/ZoomableLabel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <QLabel>
#include <QPixmap>
#include <QWheelEvent>

class ZoomableLabel : public QLabel
{
public:
explicit ZoomableLabel(QWidget *parent = nullptr);
void setOriginalPixmap(const QPixmap &pixmap);

protected:
void wheelEvent(QWheelEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;

private:
void updateImage();
void reset();

QPixmap originalPixmap;
double scaleFactor;
QPoint dragPosition;
};
Loading
Loading