Skip to content

Commit 9d37f12

Browse files
committed
macOS support: fix DXT rendering, crash-on-quit, Finder dialog, and CI
- Add built-in software DXT1/DXT3/DXT5 decoder replacing broken Compressonator decompression on ARM64 (works on all platforms) - Fix crash-on-quit from use-after-free in QTextDocument::destroyed lambda - Fix Finder file dialog by adding valid CFBundleIdentifier to Info.plist - Fix long VTF path text blocking image preview with word wrap - Fix false "DXT compression unavailable" warning for non-DXT formats - Add macOS Compressonator build-from-source in CI for DXT compression - Fix CI: clone GLM dep, patch OpenCV requirement, drop macOS Qt arch - Update Compressonator header to match Yellow-Dog-Man fork ABI
1 parent a2d58a8 commit 9d37f12

13 files changed

Lines changed: 445 additions & 277 deletions

.github/workflows/ci.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
run: >-
2626
cmake -S . -B build
2727
-DCMAKE_BUILD_TYPE=Release
28-
-DVTFLIB_USE_COMPRESSONATOR=${{ runner.os == 'Linux' && 'ON' || 'OFF' }}
28+
-DVTFLIB_USE_COMPRESSONATOR=${{ runner.os != 'Windows' && 'ON' || 'OFF' }}
2929
-DVTFCMD_IMAGE_BACKEND=stb
3030
-DBUILD_VTFEDIT_QT=OFF
3131
@@ -65,7 +65,7 @@ jobs:
6565
with:
6666
version: 6.8.3
6767
cache: true
68-
arch: ${{ runner.os == 'Windows' && 'win64_msvc2022_64' || runner.os == 'macOS' && 'clang_64' || 'linux_gcc_64' }}
68+
arch: ${{ runner.os == 'Windows' && 'win64_msvc2022_64' || runner.os == 'Linux' && 'linux_gcc_64' || '' }}
6969

7070
- name: Install additional Linux dependencies
7171
if: runner.os == 'Linux'
@@ -157,6 +157,13 @@ jobs:
157157
-always-overwrite \
158158
-verbose=2
159159
160+
# macdeployqt copies frameworks but may not fix LC_RPATH in the binary.
161+
# Add the standard rpath so @rpath references resolve at runtime.
162+
exe=dist/vtfeditqt.app/Contents/MacOS/vtfeditqt
163+
if ! otool -l "$exe" | grep -A2 LC_RPATH | grep -q '@executable_path/../Frameworks'; then
164+
install_name_tool -add_rpath @executable_path/../Frameworks "$exe"
165+
fi
166+
160167
- name: Add README
161168
shell: bash
162169
run: |

VTFEdit/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ add_executable(vtfeditqt
5454
MainWindow.cpp
5555
)
5656

57+
set_target_properties(vtfeditqt PROPERTIES
58+
MACOSX_BUNDLE_BUNDLE_NAME "QTFEdit"
59+
MACOSX_BUNDLE_GUI_IDENTIFIER "com.qtfedit.vtfeditqt"
60+
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
61+
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}"
62+
MACOSX_BUNDLE_INFO_STRING "QTFEdit - VTF/VMT Editor"
63+
)
64+
5765
target_link_libraries(vtfeditqt
5866
PRIVATE
5967
vtflib

VTFEdit/CreateVtfDialog.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ CreateVtfDialog::CreateVtfDialog(QWidget *parent) : QDialog(parent) {
110110

111111
// Disable formats we can’t encode (DXT typically requires a compressor; P8 is not supported).
112112
if(auto *model = qobject_cast<QStandardItemModel *>(format_->model())) {
113-
bool anyDisabled = false;
113+
bool dxtDisabled = false;
114114
for(int i = 0; i < format_->count(); ++i) {
115115
const auto fmt = static_cast<VTFImageFormat>(format_->itemData(i).toInt());
116116
const bool canEncode = vtflibCanEncode(fmt);
@@ -120,14 +120,14 @@ CreateVtfDialog::CreateVtfDialog(QWidget *parent) : QDialog(parent) {
120120
if(fmt == IMAGE_FORMAT_DXT1 || fmt == IMAGE_FORMAT_DXT3 || fmt == IMAGE_FORMAT_DXT5 ||
121121
fmt == IMAGE_FORMAT_DXT1_ONEBITALPHA) {
122122
it->setToolTip("DXT encoding requires a compressor (e.g. Compressonator).");
123+
dxtDisabled = true;
123124
} else {
124125
it->setToolTip("This image format is not supported for creation by this build of VTFLib.");
125126
}
126127
}
127-
anyDisabled = true;
128128
}
129129
}
130-
if(anyDisabled) {
130+
if(dxtDisabled) {
131131
compressionNote_->setText("DXT compression is unavailable on this build (Compressonator not found). "
132132
"Choose an uncompressed format (RGBA8888/BGRA8888) or install Compressonator and rebuild.");
133133
} else {

VTFEdit/MainWindow.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
13171317

13181318
infoPath_ = new QLabel("-");
13191319
infoPath_->setTextInteractionFlags(Qt::TextSelectableByMouse);
1320+
infoPath_->setWordWrap(true);
1321+
infoPath_->setMinimumWidth(80);
13201322
infoLayout->addRow("Path:", infoPath_);
13211323

13221324
infoVersion_ = new QLabel("-");
@@ -1339,6 +1341,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
13391341

13401342
infoFlags_ = new QLabel("-");
13411343
infoFlags_->setTextInteractionFlags(Qt::TextSelectableByMouse);
1344+
infoFlags_->setWordWrap(true);
13421345
infoLayout->addRow("Flags:", infoFlags_);
13431346

13441347
infoStartFrame_ = new QLabel("-");
@@ -1574,7 +1577,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
15741577
}
15751578
connect(vmtEditor_->document(), &QObject::destroyed, this, [this] {
15761579
vmtHighlighter_ = nullptr;
1577-
if(actionVmtHighlight_) actionVmtHighlight_->setChecked(false);
15781580
});
15791581
connect(vmtEditor_->document(), &QTextDocument::modificationChanged, this, [this](bool) {
15801582
updateWindowTitle();
@@ -2930,11 +2932,11 @@ void MainWindow::liveValidateVmtTick() {
29302932
void MainWindow::openFileDialog() {
29312933
QSettings s;
29322934
const QString startDir = s.value("paths/open_vtf").toString();
2933-
const QString path = QFileDialog::getOpenFileName(this, "Open VTF", startDir, "Valve Texture Format (*.vtf)");
2935+
const QString path = QFileDialog::getOpenFileName(this, "Open VTF", startDir, "Valve Texture Format (*.vtf);;All files (*)");
29342936
if(path.isEmpty()) return;
29352937
s.setValue("paths/open_vtf", QFileInfo(path).absolutePath());
29362938
// Defer until after the native file dialog fully closes.
2937-
QTimer::singleShot(0, this, [this, path] { openVtf(path); });
2939+
QTimer::singleShot(0, this, [this, path] { openPath(path); });
29382940
}
29392941

29402942
void MainWindow::openRecentFile() {
@@ -2995,7 +2997,7 @@ void MainWindow::openVmtDialog() {
29952997
if(!maybeSaveVmt()) return;
29962998
QSettings s;
29972999
const QString startDir = s.value("paths/open_vmt").toString();
2998-
const QString path = QFileDialog::getOpenFileName(this, "Open VMT", startDir, "Valve Material Type (*.vmt)");
3000+
const QString path = QFileDialog::getOpenFileName(this, "Open VMT", startDir, "Valve Material Type (*.vmt);;All files (*)");
29993001
if(path.isEmpty()) return;
30003002
s.setValue("paths/open_vmt", QFileInfo(path).absolutePath());
30013003
openVmtFromPath(path);
@@ -3051,7 +3053,7 @@ void MainWindow::openMatchingVmtFromVtf() {
30513053

30523054
QSettings s;
30533055
const QString startDir = QFileInfo(currentPath_).absolutePath();
3054-
const QString path = QFileDialog::getOpenFileName(this, "Open VMT", startDir, "Valve Material Type (*.vmt)");
3056+
const QString path = QFileDialog::getOpenFileName(this, "Open VMT", startDir, "Valve Material Type (*.vmt);;All files (*)");
30553057
if(path.isEmpty()) return;
30563058
s.setValue("paths/open_vmt", QFileInfo(path).absolutePath());
30573059
openVmtFromPath(path);
@@ -3336,7 +3338,7 @@ void MainWindow::saveVmtAs() {
33363338
QSettings s;
33373339
const QString startDir = s.value("paths/save_vmt").toString();
33383340
const QString start = startDir.isEmpty() ? suggested : QDir(startDir).filePath(suggested);
3339-
const QString path = QFileDialog::getSaveFileName(this, "Save VMT As", start, "Valve Material Type (*.vmt)");
3341+
const QString path = QFileDialog::getSaveFileName(this, "Save VMT As", start, "Valve Material Type (*.vmt);;All files (*)");
33403342
if(path.isEmpty()) return;
33413343
s.setValue("paths/save_vmt", QFileInfo(path).absolutePath());
33423344
currentVmtPath_ = path;

VTFLib/CMakeLists.txt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ if(VTFLIB_USE_COMPRESSONATOR)
5252
${PROJECT_SOURCE_DIR}/lib/linux/${CMAKE_SYSTEM_PROCESSOR}
5353
${PROJECT_SOURCE_DIR}/lib/linux/x86_64
5454
)
55+
elseif(APPLE)
56+
# macOS static libs live under lib/darwin/<arch>/ (built from source in CI).
57+
list(APPEND _compressonator_search_paths
58+
${PROJECT_SOURCE_DIR}/lib/darwin/${CMAKE_SYSTEM_PROCESSOR}
59+
${PROJECT_SOURCE_DIR}/lib/darwin/arm64
60+
${PROJECT_SOURCE_DIR}/lib/darwin/x86_64
61+
)
5562
endif()
5663

5764
if(WIN32)
@@ -116,7 +123,7 @@ if(VTFLIB_USE_COMPRESSONATOR)
116123
endif()
117124
endif()
118125
else()
119-
find_library(COMPRESSONATOR_LIB NAMES Compressonator compressonator
126+
find_library(COMPRESSONATOR_LIB NAMES Compressonator compressonator CMP_Compressonator
120127
PATHS ${_compressonator_search_paths}
121128
)
122129
if(COMPRESSONATOR_LIB)
@@ -126,6 +133,13 @@ if(VTFLIB_USE_COMPRESSONATOR)
126133
endif()
127134

128135
if(_vtflib_has_compressonator)
136+
# Link CMP_Framework if available (needed by Yellow-Dog-Man fork builds)
137+
find_library(CMP_FRAMEWORK_LIB NAMES CMP_Framework
138+
PATHS ${_compressonator_search_paths}
139+
)
140+
if(CMP_FRAMEWORK_LIB)
141+
target_link_libraries(vtflib PRIVATE ${CMP_FRAMEWORK_LIB})
142+
endif()
129143
# Link all CMP_Core variants (base, SSE, AVX)
130144
find_library(CMP_CORE_LIB NAMES CMP_Core
131145
PATHS ${_compressonator_search_paths}
@@ -136,6 +150,9 @@ if(VTFLIB_USE_COMPRESSONATOR)
136150
find_library(CMP_CORE_AVX_LIB NAMES CMP_Core_AVX
137151
PATHS ${_compressonator_search_paths}
138152
)
153+
find_library(CMP_CORE_AVX512_LIB NAMES CMP_Core_AVX512
154+
PATHS ${_compressonator_search_paths}
155+
)
139156
if(CMP_CORE_LIB)
140157
target_link_libraries(vtflib PRIVATE ${CMP_CORE_LIB})
141158
endif()
@@ -145,6 +162,9 @@ if(VTFLIB_USE_COMPRESSONATOR)
145162
if(CMP_CORE_AVX_LIB)
146163
target_link_libraries(vtflib PRIVATE ${CMP_CORE_AVX_LIB})
147164
endif()
165+
if(CMP_CORE_AVX512_LIB)
166+
target_link_libraries(vtflib PRIVATE ${CMP_CORE_AVX512_LIB})
167+
endif()
148168
target_compile_definitions(vtflib PRIVATE VTFLIB_HAS_COMPRESSONATOR)
149169
target_include_directories(vtflib PRIVATE ${PROJECT_SOURCE_DIR}/lib/include)
150170
else()

0 commit comments

Comments
 (0)