Files
imgui-java/BUILDING.md
T
RobotandClaude Sonnet 4.6 34c40304f6
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
feat: add IMGUI_USE_WCHAR32 support, cross-compile natives, publish to mvn.mrlokop.dev
- 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>
2026-04-20 10:29:43 +03:00

7.1 KiB

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

<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):

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.

# 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

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.

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

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:

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:

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:

linux64.compilerPrefix = 'x86_64-unknown-linux-gnu-'

In buildSrc/scripts/vendor_freetype.sh:

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:

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:

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 jshorts:

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:

// 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);