CI / Build Java (push) Has been cancelled
CI / Build Native (macos-latest - macos) (push) Has been cancelled
CI / Build Native (ubuntu-latest - linux) (push) Has been cancelled
CI / Build Native (ubuntu-latest - windows) (push) Has been cancelled
CI / Archive Natives (push) Has been cancelled
CI / Update Binaries (push) Has been cancelled
CI / Release (push) Has been cancelled
- Enable IMGUI_USE_WCHAR32 in imconfig.h (ImWchar = uint32_t) - Extend ImFontGlyphRangesBuilder, ImFontConfig, ImFontAtlas for 32-bit codepoints - Cross-compile natives for macOS universal, Linux x86_64 (glibc), Windows x86_64 - Publish as org.nnstd.imgui:...:1.90.0-wchar32+mrlokop2 to mvn.mrlokop.dev - Add BUILDING.md with full rebuild and publish instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
231 lines
7.1 KiB
Markdown
231 lines
7.1 KiB
Markdown
# Building imgui-java WCHAR32 Fork
|
|
|
|
This fork adds `IMGUI_USE_WCHAR32=1` support so that ImGui can handle Unicode codepoints above U+FFFF (emoji, CJK extensions, etc.). Published as `org.nnstd.imgui:imgui-java-*:1.90.0-wchar32+mrlokopN`.
|
|
|
|
## Repository
|
|
|
|
- **Maven**: `https://mvn.mrlokop.dev/releases`
|
|
- **Git**: `https://git.mrlokop.dev/shlepa/imgui-java`
|
|
|
|
## Coordinates
|
|
|
|
```xml
|
|
<repository>
|
|
<id>mrlokop</id>
|
|
<url>https://mvn.mrlokop.dev/releases</url>
|
|
</repository>
|
|
|
|
<dependency>
|
|
<groupId>org.nnstd.imgui</groupId>
|
|
<artifactId>imgui-java-binding</artifactId>
|
|
<version>1.90.0-wchar32+mrlokop2</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.nnstd.imgui</groupId>
|
|
<artifactId>imgui-java-lwjgl3</artifactId>
|
|
<version>1.90.0-wchar32+mrlokop2</version>
|
|
</dependency>
|
|
<!-- Pick one natives artifact for your platform: -->
|
|
<dependency>
|
|
<groupId>org.nnstd.imgui</groupId>
|
|
<artifactId>imgui-java-natives-macos</artifactId>
|
|
<version>1.90.0-wchar32+mrlokop2</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.nnstd.imgui</groupId>
|
|
<artifactId>imgui-java-natives-linux</artifactId>
|
|
<version>1.90.0-wchar32+mrlokop2</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.nnstd.imgui</groupId>
|
|
<artifactId>imgui-java-natives-windows</artifactId>
|
|
<version>1.90.0-wchar32+mrlokop2</version>
|
|
</dependency>
|
|
<!-- Or use the fat jar (includes all natives + LWJGL3): -->
|
|
<dependency>
|
|
<groupId>org.nnstd.imgui</groupId>
|
|
<artifactId>imgui-java-app</artifactId>
|
|
<version>1.90.0-wchar32+mrlokop2</version>
|
|
</dependency>
|
|
```
|
|
|
|
For Gradle (Kotlin DSL):
|
|
|
|
```kotlin
|
|
repositories {
|
|
maven("https://mvn.mrlokop.dev/releases")
|
|
}
|
|
|
|
dependencies {
|
|
implementation("org.nnstd.imgui:imgui-java-binding:1.90.0-wchar32+mrlokop2")
|
|
implementation("org.nnstd.imgui:imgui-java-lwjgl3:1.90.0-wchar32+mrlokop2")
|
|
runtimeOnly("org.nnstd.imgui:imgui-java-natives-linux:1.90.0-wchar32+mrlokop2")
|
|
}
|
|
```
|
|
|
|
## Version History
|
|
|
|
| Version | Linux toolchain | Notes |
|
|
|---------|-----------------|-------|
|
|
| `+mrlokop1` | musl (`x86_64-unknown-linux-musl`) | No glibc dependency; static stdlib |
|
|
| `+mrlokop2` | glibc (`x86_64-unknown-linux-gnu`) | Standard Linux distros; links libc.so.6 |
|
|
|
|
## Prerequisites (macOS build host)
|
|
|
|
All cross-compilation is done from a macOS machine.
|
|
|
|
```bash
|
|
# Java 17 (build toolchain)
|
|
sdk install java 17.0.18.1-sem # via SDKMAN
|
|
|
|
# Native build tools
|
|
brew install ant
|
|
brew install mingw-w64 # Windows cross-compiler
|
|
|
|
# Linux glibc cross-compiler (for +mrlokop2 / recommended)
|
|
brew tap messense/macos-cross-toolchains
|
|
brew install x86_64-unknown-linux-gnu
|
|
|
|
# Linux musl cross-compiler (for +mrlokop1 / no-glibc builds)
|
|
brew install x86_64-unknown-linux-musl
|
|
```
|
|
|
|
## Build Steps
|
|
|
|
### 1. Clone and initialise submodules
|
|
|
|
```bash
|
|
git clone https://git.mrlokop.dev/shlepa/imgui-java
|
|
cd imgui-java
|
|
git submodule update --init --recursive
|
|
```
|
|
|
|
### 2. Build vendored FreeType for each platform
|
|
|
|
FreeType must be cross-compiled before the JNI natives.
|
|
|
|
```bash
|
|
buildSrc/scripts/vendor_freetype.sh macos
|
|
buildSrc/scripts/vendor_freetype.sh linux
|
|
buildSrc/scripts/vendor_freetype.sh windows
|
|
```
|
|
|
|
Each invocation drops a static `libfreetype.a` into `build/vendor/freetype/lib/`. The macOS build uses `lipo` to create a universal (arm64 + x86_64) library automatically.
|
|
|
|
### 3. Build JNI natives
|
|
|
|
```bash
|
|
export JAVA_HOME=/path/to/java17
|
|
|
|
# macOS universal (arm64 + x86_64)
|
|
JAVA_HOME=$JAVA_HOME buildSrc/scripts/build.sh macos
|
|
|
|
# Linux x86_64 (glibc)
|
|
JAVA_HOME=$JAVA_HOME buildSrc/scripts/build.sh linux
|
|
|
|
# Windows x86_64 (mingw)
|
|
JAVA_HOME=$JAVA_HOME buildSrc/scripts/build.sh windows
|
|
```
|
|
|
|
Compiled natives land in:
|
|
- `bin/macos64/libimgui-java64.dylib`
|
|
- `bin/macosarm64/libimgui-java64.dylib`
|
|
- `bin/linux64/libimgui-java64.so`
|
|
- `bin/windows64/imgui-java64.dll`
|
|
|
|
### 4. Bump the version (when releasing a new patch)
|
|
|
|
Edit `build.gradle` (root), increment the `+mrlokopN` suffix:
|
|
|
|
```groovy
|
|
version = '1.90.0-wchar32+mrlokop3' // was +mrlokop2
|
|
```
|
|
|
|
### 5. Publish to Maven
|
|
|
|
Publish each platform's natives separately because the artifact classifier differs. Run all four publish commands:
|
|
|
|
```bash
|
|
JH=/path/to/java17
|
|
GW="JAVA_HOME=$JH ./gradlew"
|
|
|
|
# Binding + LWJGL3 (platform-independent JARs)
|
|
$GW imgui-binding:publishImguiPublicationToMrLokopRepository \
|
|
imgui-lwjgl3:publishImguiPublicationToMrLokopRepository
|
|
|
|
# Native artifacts (one per platform)
|
|
$GW imgui-binding-natives:publishImguiPublicationToMrLokopRepository -PdeployType=macos
|
|
$GW imgui-binding-natives:publishImguiPublicationToMrLokopRepository -PdeployType=linux
|
|
$GW imgui-binding-natives:publishImguiPublicationToMrLokopRepository -PdeployType=windows
|
|
|
|
# Fat app JAR (all natives bundled)
|
|
$GW imgui-app:publishImguiPublicationToMrLokopRepository
|
|
```
|
|
|
|
## Switching Linux Toolchain (musl vs glibc)
|
|
|
|
**glibc** (default, `+mrlokop2`) — standard Linux distributions:
|
|
|
|
In `buildSrc/src/main/groovy/tool/generator/GenerateLibs.groovy`:
|
|
```groovy
|
|
linux64.compilerPrefix = 'x86_64-unknown-linux-gnu-'
|
|
```
|
|
|
|
In `buildSrc/scripts/vendor_freetype.sh`:
|
|
```bash
|
|
linux) build_freetype "-fPIC" "--host=x86_64-unknown-linux-gnu" "lib/libfreetype.a" "x86_64-unknown-linux-gnu-gcc" ;;
|
|
```
|
|
|
|
**musl** (`+mrlokop1`) — no glibc dependency, portable:
|
|
|
|
In `GenerateLibs.groovy`:
|
|
```groovy
|
|
linux64.compilerPrefix = 'x86_64-unknown-linux-musl-'
|
|
linux64.linkerFlags = linux64.linkerFlags.replace('-Wl,-wrap,memcpy', '')
|
|
// After AntScriptGenerator.generate(), neutralise memcpy_wrap.c:
|
|
def memcpyWrap = new File("$jniDir/memcpy_wrap.c")
|
|
if (memcpyWrap.exists()) {
|
|
memcpyWrap.text = '/* disabled for musl */'
|
|
}
|
|
```
|
|
|
|
In `vendor_freetype.sh`:
|
|
```bash
|
|
linux) build_freetype "-fPIC" "--host=x86_64-unknown-linux-musl" "lib/libfreetype.a" "x86_64-unknown-linux-musl-gcc" ;;
|
|
```
|
|
|
|
## Key Changes vs Upstream
|
|
|
|
| File | Change |
|
|
|------|--------|
|
|
| `imgui-binding/src/main/native/imconfig.h` | Uncommented `#define IMGUI_USE_WCHAR32` |
|
|
| `ImFontGlyphRangesBuilder.java` | `UNICODE_CODEPOINT_MAX=0x10FFFF`; `addChar(int)`; 32-bit LE encoding in `addRanges`/`buildRanges` |
|
|
| `ImFontConfig.java` | Added `setGlyphRanges(int[])` overload |
|
|
| `ImFontAtlas.java` | `RETURN_GLYPH_2_SHORT` macro uses `sizeof(ImWchar)/sizeof(jshort)` multiplier |
|
|
| `build.gradle` | Version hardcoded to `1.90.0-wchar32+mrlokopN` |
|
|
| `publish.gradle` | `groupId=org.nnstd.imgui`, repo=`https://mvn.mrlokop.dev/releases` |
|
|
| `GenerateLibs.groovy` | Linux uses `x86_64-unknown-linux-gnu-` prefix |
|
|
| `vendor_freetype.sh` | `--host=` flags for all platforms; macOS universal via `lipo` |
|
|
|
|
## 32-bit Glyph Range Encoding
|
|
|
|
With `IMGUI_USE_WCHAR32`, `ImWchar` is `uint32_t` (4 bytes). The Java binding stores glyph ranges as `short[]` where each 32-bit codepoint is packed as two little-endian `jshort`s:
|
|
|
|
```
|
|
ranges = [lo_lo, lo_hi, hi_lo, hi_hi, ..., 0, 0]
|
|
^--- pair 1 ---^ ^--- pair 2+ ---^ terminator
|
|
```
|
|
|
|
Use `ImFontGlyphRangesBuilder.buildRanges()` or `ImFontConfig.setGlyphRanges(int[])` to handle this automatically:
|
|
|
|
```java
|
|
// int[] variant (simplest)
|
|
fontConfig.setGlyphRanges(new int[]{ 0x1F000, 0x1F9FF, 0 });
|
|
|
|
// Builder variant
|
|
ImFontGlyphRangesBuilder builder = new ImFontGlyphRangesBuilder();
|
|
builder.addText("Hello 🌍");
|
|
short[] ranges = builder.buildRanges();
|
|
fontConfig.setGlyphRanges(ranges);
|
|
```
|