GRN .grn) binary containers and modern industry-standard glTF 2.0 (.glb / .gltf) models.
Project Purpose:
This project was developed as an independent format interoperability suite strictly for the purposes of digital game preservation, community modding, and software interoperability.
Its primary objective is to liberate legacy 3D assets from the proprietary Granny 1.2b format used in classic titles such as Sacred Gold (2004/2006,Sacred.exe), enabling them to be viewed, textured, rigged, and edited in modern DCC tools (Blender, Windows 3D Viewer, Godot, Unreal Engine, Unity), and conversely re-serialized into engine-compliant Granny 1.2b files for in-game execution.
Important
Experimental Proof of Concept & AI-Assisted Notice:
This repository is strictly an experimental Proof of Concept (PoC) developed with 100% AI assistance. It is provided "as is" for educational, archival, modding, and research purposes. The code and documentation may contain errors, inaccuracies, or incomplete edge-case behavior. The authors and contributors assume no responsibility or liability for any issues, crashes, data loss, or inaccuracies arising from the use, testing, or modification of this project.
- Full C++20 Native Pipeline: High-speed, bit-accurate processing with zero external runtimes or interpreter dependencies.
- Bidirectional Conversion:
GRN -> GLB: Parses Granny 1.2b binary chunks into self-contained binary glTF 2.0 with meshes, bone hierarchies, skinning weights, animations, and embedded PBR materials.GLB -> GRN: Serializes modern glTF models into bit-accurate Granny 1.2b relational chunk hierarchies (0xCA5E0000–0xCA5EFFFF), relocation footers, and Section 0 headers.
- Skeletal Rigging & Weights: Full reconstruction of bone linkages, local TRS transforms, Inverse Bind Matrices (IBM), and normalized 4-weight skinning influences (
JOINTS_0,WEIGHTS_0). - Animation Sequencing: Decodes and encodes split keyframe tracks (position, quaternion rotation, scale-shear) and interleaved tracks with high-fidelity interpolation. Supports merging external animation tracks onto rigged models.
- Comprehensive Texture & Codec Support:
- Native C++20 Granny 1.2b Compatible VTex Codec: Fully autonomous, in-process decompressor and compressor for Format 4 (Opaque) and Format 5 (Alpha plane) with zero external runtime dependencies.
- Embedded DXT1 / BC1 and DXT5 decompressor and compressor.
- Raw uncompressed RGB / RGBA / RGBX / BGR565 image extraction and packaging.
- Loose textures in PNG, TGA (32-bit truecolor), or native VTex formats.
- Coordinate Conversion: Built-in coordinate space transformations between glTF Y-up and Granny 1.2b Z-up.
- Dual Interface Modes:
- Modern GUI: Dear ImGui interface with custom Flat Magic Rune theme, embedded rune icon, real-time logging, and batch support.
- Fast CLI: High-throughput command-line converter for batch processing and automated pipelines.
During compilation, CMake builds the core conversion engine into grn_core.lib:
add_library(grn_core STATIC
src/core/grn_parser.cpp
src/core/grn_writer.cpp
src/codecs/dxt_codec.cpp
src/codecs/tga_png.cpp
src/codecs/vtex_codec.cpp
src/gltf/glb_reader.cpp
src/gltf/glb_writer.cpp
src/converter/converter.cpp
)grn_core.lib is not an external or proprietary library — it is our internal static library target compiled directly from src/. It is intentionally built as a static library (.lib) rather than a dynamic shared library (.dll) for key technical reasons:
- Self-Contained Standalone Executable:
- Compiling statically embeds all parsing, conversion, and codec code directly inside
grn_converter.exe. - Distributing or moving the application only requires a single executable; no loose
grn_core.dllis required.
- Compiling statically embeds all parsing, conversion, and codec code directly inside
- Zero DLL Export Overhead & Clean C++ Types:
- A Windows
.dllrequires annotating every public class, function, and template instantiation (std::vector,std::string,std::optional) with__declspec(dllexport)/__declspec(dllimport)to prevent MSVC runtime heap boundary mismatches. - A static library allows native C++20 data structures to be shared seamlessly between the core engine and unit tests without macro boilerplate or DLL boundary overhead.
- A Windows
- Link-Time Optimization (LTO / LTCG):
- The compiler and linker can inline math routines, vertex unpackers, and coordinate transforms across translation units directly into call sites, optimizing code size and runtime performance.
- Shared by Unit Tests Without Redundant Compilation:
- The 6 unit test executables in
tests/link directly againstgrn_core.lib, eliminating the need to recompile the converter codebase 7 separate times.
- The 6 unit test executables in
Classic games built on Granny 1.2b (such as Sacred Gold) compress high-resolution character, creature, and environmental diffuse textures into Granny 1.2b compatible VTex texture streams:
- Format 4 (
VTexOpaque): Opaque video texture stream without alpha channel (e.g.BLACK_MAGICIAN.grn). - Format 5 (
VTexAlpha): Video texture stream carrying a dedicated full-resolution Alpha cutout plane (e.g.BLACK_RIDER.grn).
Previously, modders were forced to rely on legacy proprietary binaries or placeholder textures. open-grn-converter provides a 100% independent, native C++20 implementation embedded directly in grn_core.lib:
- Zero External Runtime Dependencies: Runs cross-platform with 0 external codec modules or external executables.
-
Bitstream Decoding:
- Implements LSB-first bitstream parsing with 32-bit boundary alignment (
Align32()). - Supports all standard Granny 1.2b compatible macroblock types:
BLOCK_SKIP,BLOCK_SCALED,BLOCK_RUN,BLOCK_INTRA(via AAN integer IDCT),BLOCK_FILL,BLOCK_PATTERN, andBLOCK_RAW. - Sequential plane reconstruction: Alpha (
$W \times H$ ), Luma Y ($W \times H$ ), Chroma Cr ($\frac{W+1}{2} \times \frac{H+1}{2}$ ), Chroma Cb ($\frac{W+1}{2} \times \frac{H+1}{2}$ ). - Full BT.601 integer color recombination into 32-bit RGBA.
- Implements LSB-first bitstream parsing with 32-bit boundary alignment (
-
Bitstream Encoding (
encode_vtex):- Automatic alpha plane detection: analyzes pixel buffer alpha channel; if any pixel
$A < 250$ , selects Format 5, otherwise Format 4. - Planar decomposition and 2x2 box filtering for chroma subsampling.
- Fast macroblock encoding into
BLOCK_FILL,BLOCK_PATTERN, andBLOCK_RAWwith identity Huffman bundle streaming. - Serializes Granny 1.2b compatible 44-byte container headers and frame index tables for direct in-game execution.
- Automatic alpha plane detection: analyzes pixel buffer alpha channel; if any pixel
-
Verified Compatibility:
- Validated across all 116 original Sacred Gold character models (
test_grn/GRN_ORIGINAL), achieving 100% conversion success with 0 crashes, 0 validator errors, and 0 placeholder textures.
- Validated across all 116 original Sacred Gold character models (
open-grn-converter/
├── CMakeLists.txt # Primary C++20 CMake build configuration
├── CMakePresets.json # One-click build presets for Visual Studio & CLI
├── vcpkg.json # C++ dependency manifest (glfw, imgui, nlohmann-json, stb, glad)
├── LICENSE # MIT License
├── README.md # Documentation, architectural notes, and usage guide
├── .gitignore # Configured strictly for C++ / CMake / MSVC / vcpkg
│
├── src/ # C++20 Converter Source Code
│ ├── cli/ # CLI entry point and argument parsing (cli_main.cpp)
│ ├── codecs/ # DXT1, TGA, PNG, and VTex image codecs
│ ├── converter/ # Bidirectional orchestration pipeline and options
│ ├── core/ # Binary GRN parser and serializer (Granny 1.2b)
│ ├── gltf/ # glTF 2.0 / GLB reader (cgltf) and writer
│ ├── gui/ # Dear ImGui GUI app, Flat Magic Rune theme, icon, and file dialogs
│ └── main.cpp # Application launcher (auto-detects GUI vs CLI)
│
├── resources/ # Application assets (icon.ico, icon.png, .rc file)
├── third_party/cgltf/ # Header-only C glTF 2.0 parsing and writing library
├── validator/ # Khronos glTF Validator for official compliance checks
│
├── test_grn/ # Sample test assets (models, animations, GLB references)
└── tests/ # C++ automated CTest suite:
├── test_codecs.cpp # DXT1, TGA, PNG, and VTex codec tests
├── test_parser.cpp # GRN binary container chunk parser tests
├── test_writer.cpp # GRN container serializer tests
├── test_roundtrip.cpp # Bidirectional GRN <-> GLB roundtrip tests
├── test_texture_hue.cpp # Texture manipulation & pipeline verification
└── test_viewer_compat.cpp # Live debugger tests verifying 0 crashes in Granny viewer
- C++20 Compiler: Visual Studio 2022 / 2026 (MSVC), Clang-cl, or GCC 12+.
- CMake: Version 3.22 or higher.
- vcpkg: Microsoft C++ Library Manager (used to satisfy
glfw3,imgui,nlohmann-json,stb, andglad).
# 1. Clone repository
git clone https://github.com/karolak6612/open-grn-converter.git
cd open-grn-converter
# 2. Configure with CMake and vcpkg toolchain
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
# 3. Build Release executable and test suite
cmake --build build --config Release -j# Configure using preset
cmake --preset release
# Build using preset
cmake --build --preset release(Alternatively, open the repository folder in Visual Studio or VS Code with the CMake Tools extension, select the release preset, and click Build).
The compiled binary will be generated at:
build/Release/grn_converter.exe
The application automatically selects the appropriate mode:
- If run without arguments (or launched from Windows Explorer by double-clicking), it opens the Graphical User Interface (GUI).
- If run with command-line arguments, it runs the high-speed Command Line Interface (CLI).
Launch grn_converter.exe directly or pass --gui:
./build/Release/grn_converter.exeGUI Features:
-
Single Model Mode: Convert an individual
.grnor.glbfile with drag-and-drop or browse buttons. -
Animation Merge: Select an optional animation
.grnfile (e.g.WOGG_ATTACK_STAB_A.grn) to embed animation tracks directly into the exported.glb. -
Batch Processing Mode: Recursively convert an entire folder of
.grnor.glbfiles with real-time progress. -
Scaling Controls: Adjust a uniform scaling factor or specify target height in Sacred game units (e.g.
73.0for player characters,107.0for street posts). -
Coordinate Conversion: Built-in toggle for Y-up (glTF standard)
$\longleftrightarrow$ Z-up (Granny/Sacred standard). - Real-Time Log Console: Color-coded conversion logs and progress tracking.
# Basic file conversions
./build/Release/grn_converter.exe model.grn model.glb
./build/Release/grn_converter.exe model.glb model.grn
# Merge external animation track onto a character model
./build/Release/grn_converter.exe character.grn character_attack.glb --anim attack.grn
# Batch process an entire folder recursively
./build/Release/grn_converter.exe path/to/models/ path/to/output/ --batch
# Scale model to target game height (e.g. 73 units for Seraphim)
./build/Release/grn_converter.exe hero.glb hero.grn --target-height 73.0
# Export loose textures instead of embedding
./build/Release/grn_converter.exe model.grn model.glb --no-embed-textures --texture-format png
# View full options reference
./build/Release/grn_converter.exe --help| Option | Description |
|---|---|
-b, --batch |
Batch process all compatible files in the input folder recursively |
--anim <path> |
External animation .grn track to merge into the output model |
--no-embed-textures |
Save textures as loose files next to model instead of embedding |
--texture-format <fmt> |
Format for loose textures: tga (default 32-bit), png, or vtex |
--no-vtex |
Disable VTex video codec; fall back to uncompressed or loose files |
-t, --textures-dir <dir> |
Search directory for external textures |
--scale <val> |
Uniform scale multiplier applied to geometry/bones |
--target-height <val> |
Target height in game units (e.g. 73 for character, 107 for post) |
--meters |
Standard glTF metric conversion (scale = 39.37 inches/meter) |
--z-up |
Preserve native Z-up coordinates (default converts to glTF Y-up) |
--gui |
Force launching the Dear ImGui GUI window |
-h, --help |
Display help message and exit |
Run the automated CTest suite from the build folder:
ctest --test-dir build -C Release --output-on-failure| Test Name | Source File | Description |
|---|---|---|
test_codecs |
tests/test_codecs.cpp |
Validates DXT1/BC1, TGA, PNG, and VTex image codecs |
test_parser |
tests/test_parser.cpp |
Verifies low-level Granny 1.2b binary container chunk parsing |
test_writer |
tests/test_writer.cpp |
Validates binary Granny 1.2b container serialization |
test_roundtrip |
tests/test_roundtrip.cpp |
End-to-end GRN -> GLB -> GRN roundtrip mesh & skeleton fidelity |
test_texture_hue |
tests/test_texture_hue.cpp |
Texture pipeline validation and color channel transformations |
test_viewer_compat |
tests/test_viewer_compat.cpp |
Runs exported models under the original Granny viewer to ensure 0 crashes |
Note
Granny Viewer (gr2_viewer.exe) is proprietary software and is NOT included in this repository.
- Automatic Skipping: If
gr2_viewer.exeis not present,test_viewer_compatwill automatically detect its absence, display[SKIP], and exit cleanly with return code 0. The entire test suite will still report 100% passed. - Enabling Live Viewer Testing (Optional): If you possess a legitimate copy of
gr2_viewer.exe, you can enable full live viewer verification by placinggr2_viewer.exeinto:- The repository root (
./gr2_viewer.exe), OR - The binary output folder (
./build/Release/gr2_viewer.exe).
- The repository root (
- When present,
test_viewer_compatlaunches the viewer under the Windows Debugging API (DEBUG_PROCESS), monitors the process for memory access violations or unhandled exceptions, and confirms that our converted models render cleanly with zero crashes. .gitignoreis explicitly configured to ignoregr2_viewer.exeto prevent proprietary binaries from ever being committed.
This project incorporates or links against the following third-party open-source libraries:
| Library | License | Author / Copyright | Description |
|---|---|---|---|
| cgltf | MIT License | Copyright (c) 2018-2024 Johannes Kuhlmann | Single-file C glTF 2.0 parser and writer bundled in third_party/cgltf/. |
| Dear ImGui | MIT License | Copyright (c) 2014-2026 Omar Cornut | Immediate mode graphical user interface library used for the GUI frontend. |
| GLFW | zlib/libpng License | Copyright (c) 2002-2006 Marcus Geelnard, 2006-2019 Camilla Löwy | Window creation, OpenGL context initialization, and input handling. |
| GLAD | MIT / Apache 2.0 | Copyright (c) 2013-2020 David Herberth | Multi-language Vulkan/GL/GLES/EGL loader generator. |
| nlohmann/json | MIT License | Copyright (c) 2013-2025 Niels Lohmann | Modern JSON for C++ used for glTF chunk generation and metadata. |
| stb | MIT / Public Domain | Copyright (c) 2017 Sean Barrett | stb_image.h and stb_image_write.h image decoding and encoding routines. |
| glTF-Validator | Apache License 2.0 | Copyright (c) 2016-2024 The Khronos Group Inc. | Command-line tool and JSON schemas in validator/ for official glTF 2.0 specification validation. |
Individual license notices for bundled components can be found in their respective source files or under validator/LICENSE and validator/NOTICES.
This project is licensed under the MIT License. See LICENSE for details.
This repository is an independent, open-source experimental research and digital preservation project. It is not affiliated with, associated with, sponsored by, endorsed by, or in any way officially connected with RAD Game Tools, Epic Games, Inc., Ascaron Entertainment, or any of their subsidiaries or affiliates.
All trademarks, registered trademarks, service marks, trade names, and brand names referenced in this repository are the property of their respective owners. Any reference to specific third-party games, formats, engines, or company names is made solely for the purposes of identification, technical description, software interoperability, community modding, and digital game preservation.