From a0355c9b897281d0bfea48bec9d490724ecabd96 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Sun, 12 Apr 2026 17:54:45 -0500 Subject: Add NIF previewer plugin with Linux-specific fixes Vendored from github.com/Parapets/mo2-preview_nif and adapted for Linux: - BSA texture resolution via MO2 virtual tree with case-insensitive fallback walk (Linux FS is case-sensitive; NIFs reference textures with arbitrary case against files on disk) - Process-wide cached BSA candidate list, keyed by profile path, priority-sorted, filtering disabled mods - Path backslash normalization before loose-file lookup - Polygon offset on SLSF1_Decal-flagged shapes to break z-ties with coincident base meshes (road decals, moss overlays) - Opaque framebuffer via glColorMask alpha lock so alpha-blended shapes can't bleed the dialog background through the preview area - QMouseEvent::globalPosition().toPoint() for Qt6 compatibility Preview dialog behavior (organizercore.cpp): - Switch previewFile and previewFileWithAlternatives from stack-allocated exec() to heap + ApplicationModal + show() + WA_DeleteOnClose. - Parent passed as nullptr so preview lifetime is decoupled from the stack-allocated ModInfoDialog that spawns it. Nested exec() inside the enclosing dialog's exec() was softlocking on close. Co-Authored-By: Claude Opus 4.6 (1M context) --- libs/preview_nif/src/TextureManager.h | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 libs/preview_nif/src/TextureManager.h (limited to 'libs/preview_nif/src/TextureManager.h') diff --git a/libs/preview_nif/src/TextureManager.h b/libs/preview_nif/src/TextureManager.h new file mode 100644 index 0000000..7ba1c9a --- /dev/null +++ b/libs/preview_nif/src/TextureManager.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +class TextureManager +{ +public: + TextureManager(MOBase::IOrganizer* organizer); + ~TextureManager() = default; + TextureManager(const TextureManager&) = delete; + TextureManager(TextureManager&&) = delete; + TextureManager& operator=(const TextureManager&) = delete; + TextureManager& operator=(TextureManager&&) = delete; + + void cleanup(); + + QOpenGLTexture* getTexture(const std::string& texturePath); + QOpenGLTexture* getTexture(QString texturePath); + + QOpenGLTexture* getErrorTexture(); + QOpenGLTexture* getBlackTexture(); + QOpenGLTexture* getWhiteTexture(); + QOpenGLTexture* getFlatNormalTexture(); + +private: + QOpenGLTexture* loadTexture(QString texturePath); + QOpenGLTexture* makeTexture(const gli::texture& texture); + QOpenGLTexture* makeSolidColor(QVector4D color); + + QString resolvePath(const MOBase::IPluginGame* game, QString path); + + // Build priority-sorted BSA candidate list. Shared process-wide, keyed by + // the current instance's profile path so switching instances rebuilds. + // Conflict semantics: only active mods contribute, highest profile + // priority first, then vanilla archives. No plugin-attachment filter — + // matches BodySlide's "load all BSAs" approach which is what MO2's + // virtual data tree effectively does. + const QStringList& bsaCandidates(); + void rebuildBsaCandidates(); + + MOBase::IOrganizer* m_MOInfo; + QOpenGLTexture* m_ErrorTexture = nullptr; + QOpenGLTexture* m_BlackTexture = nullptr; + QOpenGLTexture* m_WhiteTexture = nullptr; + QOpenGLTexture* m_FlatNormalTexture = nullptr; + + std::map m_Textures; +}; -- cgit v1.3.1