diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2cf29b..f8cf0b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,15 @@ name: CI -on: [ push, pull_request ] + +on: + push: + branches: + - main + tags: + - v* + pull_request: + branches: + - main + jobs: build-java: name: Build Java @@ -20,34 +30,33 @@ jobs: - name: Build run: ./gradlew buildAll + # This helps to upload only jar files into the build artifact + - name: Copy Build Results to Temp + run: | + mkdir -p tmp/ + cp imgui-app/build/libs/*.jar tmp/ + cp imgui-binding/build/libs/*.jar tmp/ + cp imgui-lwjgl3/build/libs/*.jar tmp/ + - name: Upload Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: java-libraries - path: | - imgui-app/build/libs/*.jar - imgui-binding/build/libs/*.jar - imgui-lwjgl3/build/libs/*.jar + path: tmp/*.jar build-natives: - name: Build Native (${{ matrix.target.type }}${{ matrix.freetype && ', freetype' || '' }}) + name: Build Native (${{ matrix.target.os }} - ${{ matrix.target.type }}) + needs: build-java strategy: fail-fast: false matrix: - freetype: [ true, false ] target: - - os: ubuntu-latest - type: windows - expected: /tmp/imgui/libsNative/windows64/imgui-java64.dll - os: ubuntu-latest type: linux - expected: /tmp/imgui/libsNative/linux64/libimgui-java64.so + - os: ubuntu-latest + type: windows - os: macos-latest type: macos - expected: /tmp/imgui/libsNative/macosx64/libimgui-java64.dylib - - os: macos-latest - type: macosarm64 - expected: /tmp/imgui/libsNative/macosxarm64/libimgui-javaarm64.dylib runs-on: ${{ matrix.target.os }} steps: - name: Checkout Repository and Submodules @@ -63,58 +72,44 @@ jobs: distribution: liberica cache: gradle - - name: Ant Version - run: ant -version - - - name: Install MinGW-w64/GCC/G++ (Linux & Windows) - if: matrix.target.os == 'ubuntu-latest' + - name: Install Dependencies (for Windows build) + if: matrix.target.type == 'windows' run: sudo apt install mingw-w64 - - name: FreeType - Install (Linux) - if: matrix.target.os == 'ubuntu-latest' && matrix.target.type == 'linux' && matrix.freetype == true - run: sudo apt install libfreetype6-dev - - - name: FreeType - Install (Windows) - if: matrix.target.os == 'ubuntu-latest' && matrix.target.type == 'windows' && matrix.freetype == true - run: | - sudo mkdir /freetype - sudo tar -xzf ./vendor/freetype-2.12.1.tar.gz -C /freetype --strip-components=1 - cd /freetype - sudo ./configure --with-zlib=no --with-bzip2=no --with-png=no --with-harfbuzz=no --with-brotli=no --host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32 - sudo make - sudo make install - - - name: FreeType - Install (MacOS) - if: matrix.target.os == 'macos-latest' && matrix.freetype == true - run: | - sudo mkdir /opt/freetype - sudo tar -xzf ./vendor/freetype-2.12.1.tar.gz -C /opt/freetype --strip-components=1 - cd /opt/freetype - sudo ./configure CFLAGS="-arch arm64 -arch x86_64" --with-zlib=no --with-bzip2=no --with-png=no --with-harfbuzz=no --with-brotli=no - sudo make - sudo make install - - name: Build - run: ./gradlew imgui-binding:generateLibs -Denvs=${{ matrix.target.type }} -Dfreetype=${{ matrix.freetype }} + run: | + chmod +x buildSrc/scripts/build.sh + buildSrc/scripts/build.sh ${{ matrix.target.type }} - name: Upload Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: ${{ matrix.freetype && 'native-libraries-with-freetype' || 'native-libraries' }} - if-no-files-found: error - path: ${{ matrix.target.expected }} + name: native-library-${{ matrix.target.type }} + path: /tmp/imgui/dst/ + + # This required to pack all native libraries into single archive + archive-natives: + name: Archive Natives + runs-on: ubuntu-latest + needs: build-natives + steps: + - name: Merge Artifacts + uses: actions/upload-artifact/merge@v4 + with: + name: native-libraries + pattern: native-library-* update-bin: name: Update Binaries if: github.ref == 'refs/heads/main' && !github.event.repository.fork # runs only on the main branch and not forks (sometimes people do PRs from the main branch) runs-on: ubuntu-latest - needs: build-natives + needs: archive-natives steps: - name: Checkout Repository uses: actions/checkout@v4 - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: /tmp/artifacts @@ -133,9 +128,7 @@ jobs: - name: Update if: steps.cmp-binding-hash.outcome != 'success' - run: | - mv /tmp/artifacts/native-libraries/* bin/ - mv /tmp/artifacts/native-libraries-with-freetype/* bin/freetype/ + run: mv /tmp/artifacts/native-libraries/* bin/ - name: Commit if: steps.cmp-binding-hash.outcome != 'success' @@ -148,7 +141,7 @@ jobs: name: Release if: startsWith(github.ref, 'refs/tags/v') # if tag starts with "v" runs-on: ubuntu-latest - needs: [ build-java, build-natives ] + needs: [ build-java, archive-natives ] steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -163,7 +156,7 @@ jobs: cache: gradle - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: out/artifacts @@ -171,7 +164,6 @@ jobs: run: | mkdir out/archives zip -rj out/archives/native-libraries out/artifacts/native-libraries - zip -rj out/archives/native-libraries-with-freetype out/artifacts/native-libraries-with-freetype zip -rj out/archives/java-libraries out/artifacts/java-libraries - name: Publish diff --git a/README.md b/README.md index a4080d8..65f3919 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ To understand how to use ImGui Java - read official [documentation](https://gith Binding adopts C++ API for Java, but almost everything can be used in the same manner. ImGui Java has a ready to use implementation for GLFW and OpenGL API using [LWJGL3](https://www.lwjgl.org/) library. See `imgui-lwjgl3` module.
-Implementation is optional, yet optional to use. Advantage of Dear ImGui is total portability, so feel free to copy-paste classes or write your own implementations. +Implementation is optional to use. Advantage of Dear ImGui is total portability, so feel free to copy-paste classes or write your own implementations. Additionally, there is an `imgui-app` module, which provides **a high abstraction layer**.
It hides all low-level code under one class to extend. With it, you can build your GUI application instantly. @@ -70,6 +70,10 @@ Gradle and Maven dependencies could be used for this purpose as well. Take a note, that integration itself is a very flexible process. It could be done in one way or another. If you just need a framework for your GUI - use [Application](#application) module. Otherwise, if you need more control, the best way is not just to repeat steps, but to understand what each step does. +### For macOS M-chip users + +The macOS version of the binding is compiled as a universal binary. This means you can use it on both x86_64 and aarch64 platforms without any additional actions. + ## Application If you don't care about OpenGL and other low-level stuff, then you can use application layer from `imgui-app` module. @@ -176,7 +180,6 @@ For simplicity, example of dependencies for Gradle / Maven only shows how to add | imgui-java-natives-windows | Windows | | imgui-java-natives-linux | Linux | | imgui-java-natives-macos | macOS | -| imgui-java-natives-macos-arm64 | macOS-arm64 | Take a note, that you also need to add dependencies to [LWJGL](https://www.lwjgl.org/) library. Examples below shows how to do it as well. @@ -282,10 +285,10 @@ dependencies { Raw Jars 1. Go to the [release page](https://github.com/SpaiR/imgui-java/releases/latest); -2. Download `java-libraries.zip` and `native-libraries.zip` (`native-libraries-with-freetype.zip` for FreeType font rendering); +2. Download `java-libraries.zip` and `native-libraries.zip`; 3. Get `imgui-binding-${version}.jar` and `imgui-lwjgl3-${version}.jar` from `java-libraries`, and binary libraries for required OS from `native-libraries` archive; 4. Add jars to your classpath; -5. Provide a VM option with location of files from the `native-libraries` (or `native-libraries-with-freetype`) archive. +5. Provide a VM option with location of files from the `native-libraries` archive. VM option example: - **-Dimgui.library.path=_${path}_** @@ -307,7 +310,6 @@ If using Java 9 modules, ImGui Java has Automatic Module Names: | imgui-java-natives-windows | imgui.natives.windows | | imgui-java-natives-linux | imgui.natives.linux | | imgui-java-natives-macos | imgui.natives.macos | -| imgui-java-natives-macos-arm64 | imgui.natives.macos-arm64 | ## Extensions @@ -331,67 +333,14 @@ See examples in the `example` module for more information about how to use them. ## Freetype -By default, Dear ImGui uses stb-truetype to render fonts. Yet there is an option to use FreeType font renderer. -Go to the [imgui_freetype](https://github.com/ocornut/imgui/tree/256594575d95d56dda616c544c509740e74906b4/misc/freetype) to read about the difference. -Binding has this option too. Freetype especially useful when you use custom font with small (~<16px) size. -If you use the default font or a large font, stb will be fine for you. +By default, Dear ImGui uses stb-truetype to render fonts. However, there is an option to use the FreeType font renderer. +To learn about the differences, visit the [imgui_freetype](https://github.com/ocornut/imgui/tree/256594575d95d56dda616c544c509740e74906b4/misc/freetype) page. -There are two types of precompiled binaries: 1. with stb (the default one) 2. with freetype. -You can decide by yourself, which kind of libraries for any system you want to use. +This binding also supports the FreeType option. +FreeType is statically pre-compiled into the library, meaning it is **enabled by default** and there is no option to disable it. +Therefore, you can freely use `ImGuiFreeTypeBuilderFlags` in your font configuration. -Take a note, that for Linux and macOS users using of freetype will add a dependency to the `libfreetype` itself. -This is not the case for Windows users, since `dll` binaries are compiled fully statically and already include freetype in themselves. - -**For fully portable application** use default binaries.
-You can still use freetype binaries for Windows builds without worry though. - -**For better fonts** use freetype binaries.
-Don't forget to make clear for your Linux/Mac users, that they will need to install freetype on their systems as well. - -### Dependencies - -![Maven Central](https://img.shields.io/maven-central/v/io.github.spair/imgui-java-binding?color=green&label=version&style=flat-square) - -Use the same native libraries as you would, but with `-ft` suffix in the end. - -
- Modified Gradle Example - - ``` - repositories { - mavenCentral() - } - - ext { - lwjglVersion = '3.3.3' - imguiVersion = "${version}" - } - - dependencies { - implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion") - - ['', '-opengl', '-glfw'].each { - implementation "org.lwjgl:lwjgl$it:$lwjglVersion" - implementation "org.lwjgl:lwjgl$it::natives-windows" - } - - implementation "io.github.spair:imgui-java-binding:$imguiVersion" - implementation "io.github.spair:imgui-java-lwjgl3:$imguiVersion" - - // This is the main difference - implementation "io.github.spair:imgui-java-natives-windows-ft:$imguiVersion" - } - ``` -
- -| Native Binaries With FreeType | System | -|-----------------------------------|-------------| -| imgui-java-natives-windows-ft | Windows | -| imgui-java-natives-linux-ft | Linux | -| imgui-java-natives-macos-ft | macOS | -| imgui-java-natives-macos-arm64-ft | macOS-arm64 | - -If you're using raw dll/so files, go to the [release page](https://github.com/SpaiR/imgui-java/releases/latest) and use libraries from the `native-libraries-with-freetype.zip` archive. +If you prefer not to use the FreeType font renderer, you will need to build your own binaries and use them instead. # Binding Notice @@ -408,7 +357,7 @@ Read [javadoc](https://javadoc.io/doc/io.github.spair/imgui-java-binding) and so Ensure you've downloaded git submodules. That could be achieved: - When cloning the repository: `git clone --recurse-submodules https://github.com/SpaiR/imgui-java.git` -- When the repository cloned: `git submodule init` + `git submodule update` +- When the repository cloned: `git submodule init` and `git submodule update` ### Windows @@ -418,6 +367,7 @@ Ensure you've downloaded git submodules. That could be achieved: * Mingw-w64 (recommended way: use [MSYS2](https://www.msys2.org/) and install [mingw-w64-x86_64-toolchain](https://packages.msys2.org/group/mingw-w64-x86_64-toolchain) group) - Build with: `./gradlew imgui-binding:generateLibs -Denvs=windows -Dlocal` - Run with: `./gradlew example:run -PlibPath="../imgui-binding/build/libsNative/windows64"` + - Always use `-Dlocal` flag. ### Linux @@ -431,15 +381,20 @@ Ensure you've downloaded git submodules. That could be achieved: - Build with: `./gradlew imgui-binding:generateLibs -Denvs=macos -Dlocal` - Run with: `./gradlew example:run -PlibPath=../imgui-binding/build/libsNative/macosx64` -### macOS-arm64 +### macOS (arm64) - Check dependencies from "Linux" section and make sure you have them installed. - Build with: `./gradlew imgui-binding:generateLibs -Denvs=macosarm64 -Dlocal` - Run with: `./gradlew example:run -PlibPath=../imgui-binding/build/libsNative/macosxarm64` -In `envs` parameter next values could be used `windows`, `linux` or `macos` or `macosarm64`.
+In `envs` parameter next values could be used `windows`, `linux` or `macos` or `macosarm64`. + `-Dlocal` is optional and means that natives will be built under the `./imgui-binding/build/` folder. Otherwise `/tmp/imgui` folder will be used. -On Windows always use local build. + +## Freetype + +To build a version of the libraries with FreeType, you need to run the `buildSrc/scripts/vendor_freetype.sh` script first. +This script configures the FreeType library to be statically compiled into your project. # License diff --git a/bin/README.md b/bin/README.md index 4038f32..5811c4f 100644 --- a/bin/README.md +++ b/bin/README.md @@ -1,10 +1,25 @@ -Folder contains libraries used by the binding and `binding.sha1` sum of the `imgui-binding/src/main` directory libraries has been built upon. +### Overview -Provide `imgui.library.path` (or `java.library.path`) VM option to the folder with one of those file (ex: `-Dimgui.library.path=./folder/path`). -In the same way you can use 'java.library.path' option instead. +The folder contains libraries used by the binding and the `binding.sha1` checksum for the `imgui-binding/src/main` directory that the libraries are built upon. These libraries are utilized during the release process. -By default, binding expects `imgui-java64` file name. -You can change that by using `imgui.library.name` VM option (ex: `-Dimgui.library.name=custom-lib-name.dll`). +### Specifying the Library Path + +To specify the folder containing these files, provide the `imgui.library.path` (or `java.library.path`) VM option. For example: +``` +-Dimgui.library.path=./folder/path +``` +You can also use the `java.library.path` option in the same manner. + +### Changing the Library Name + +By default, the binding expects the file name `imgui-java64`. You can change this by using the `imgui.library.name` VM option. For example: +``` +-Dimgui.library.name=custom-lib-name.dll +``` + +### Expected Library File Names + +The expected library file names for different operating systems are: | OS | Library | |---------|-----------------------| @@ -12,6 +27,11 @@ You can change that by using `imgui.library.name` VM option (ex: `-Dimgui.librar | Linux | libimgui-java64.so | | macOS | libimgui-java64.dylib | -Freetype directory contains same libraries, but with Freetype support. +### Additional Information -Hash sum in the `binding.sha1` file is used in CI to see, if there is a need to update native binaries. +- All libraries include statically compiled **FreeType**. +- The macOS version is a universal library and support x86_64 and arm64 architectures. + +### Continuous Integration + +The hash sum in the `binding.sha1` file is used in continuous integration (CI) to determine if there is a need to update the native binaries. diff --git a/bin/freetype/imgui-java64.dll b/bin/freetype/imgui-java64.dll deleted file mode 100644 index a8a3f46..0000000 Binary files a/bin/freetype/imgui-java64.dll and /dev/null differ diff --git a/bin/freetype/libimgui-java64.dylib b/bin/freetype/libimgui-java64.dylib deleted file mode 100644 index c72a40a..0000000 Binary files a/bin/freetype/libimgui-java64.dylib and /dev/null differ diff --git a/bin/freetype/libimgui-java64.so b/bin/freetype/libimgui-java64.so deleted file mode 100644 index 5a1cb1e..0000000 Binary files a/bin/freetype/libimgui-java64.so and /dev/null differ diff --git a/bin/freetype/libimgui-javaarm64.dylib b/bin/freetype/libimgui-javaarm64.dylib deleted file mode 100644 index 1c726d4..0000000 Binary files a/bin/freetype/libimgui-javaarm64.dylib and /dev/null differ diff --git a/bin/libimgui-javaarm64.dylib b/bin/libimgui-javaarm64.dylib deleted file mode 100644 index 7205493..0000000 Binary files a/bin/libimgui-javaarm64.dylib and /dev/null differ diff --git a/buildSrc/scripts/build.sh b/buildSrc/scripts/build.sh new file mode 100755 index 0000000..d7d17d6 --- /dev/null +++ b/buildSrc/scripts/build.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +echo "Setting base directory and navigating to project root..." +BASEDIR=$(dirname "$0") +cd "$BASEDIR"/../.. || exit 1 +echo "Navigated to $(pwd)" + +# Check if vendor type argument is provided +if [ -z "$1" ]; then + echo "Vendor type is required" + exit 1 +fi + +VTYPE=$1 +echo "Vendor type set to '$VTYPE'" + +# Make the vendor FreeType script executable and run it +echo "Making vendor FreeType script executable and running it..." +chmod +x buildSrc/scripts/vendor_freetype.sh +buildSrc/scripts/vendor_freetype.sh "$VTYPE" +if [ $? -ne 0 ]; then + echo "Vendor FreeType script failed" + exit 1 +fi +echo "Vendor FreeType script completed successfully" + +# Create the destination directory for imgui libraries +echo "Creating destination directory for imgui libraries..." +mkdir -p /tmp/imgui/dst +echo "Directory /tmp/imgui/dst created successfully" + +# Function to check if a file exists +check_file_exists() { + if [ ! -f "$1" ]; then + echo "File $1 not found!" + exit 1 + fi +} + +# Determine build process based on vendor type +case "$VTYPE" in + windows) + echo "Running Gradle task for Windows..." + ./gradlew imgui-binding:generateLibs -Denvs=windows -Dfreetype=true + if [ $? -ne 0 ]; then + echo "Gradle task for Windows failed" + exit 1 + fi + + echo "Checking if the generated DLL exists..." + check_file_exists /tmp/imgui/libsNative/windows64/imgui-java64.dll + + echo "Copying the generated DLL to the destination directory..." + cp /tmp/imgui/libsNative/windows64/imgui-java64.dll /tmp/imgui/dst/imgui-java64.dll + if [ $? -ne 0 ]; then + echo "Failed to copy DLL to /tmp/imgui/dst/imgui-java64.dll" + exit 1 + fi + echo "DLL copied to /tmp/imgui/dst/imgui-java64.dll successfully" + ;; + linux) + echo "Running Gradle task for Linux..." + ./gradlew imgui-binding:generateLibs -Denvs=linux -Dfreetype=true + if [ $? -ne 0 ]; then + echo "Gradle task for Linux failed" + exit 1 + fi + + echo "Checking if the generated SO file exists..." + check_file_exists /tmp/imgui/libsNative/linux64/libimgui-java64.so + + echo "Copying the generated SO file to the destination directory..." + cp /tmp/imgui/libsNative/linux64/libimgui-java64.so /tmp/imgui/dst/libimgui-java64.so + if [ $? -ne 0 ]; then + echo "Failed to copy SO file to /tmp/imgui/dst/libimgui-java64.so" + exit 1 + fi + echo "SO file copied to /tmp/imgui/dst/libimgui-java64.so successfully" + ;; + macos) + echo "Running Gradle task for macOS and macOS ARM..." + ./gradlew imgui-binding:generateLibs -Denvs=macos,macosarm64 -Dfreetype=true + if [ $? -ne 0 ]; then + echo "Gradle task for macOS failed" + exit 1 + fi + + echo "Checking if the generated DYLIB files exist..." + check_file_exists /tmp/imgui/libsNative/macosx64/libimgui-java64.dylib + check_file_exists /tmp/imgui/libsNative/macosxarm64/libimgui-java64.dylib + + echo "Creating a universal library using lipo..." + lipo -create -output /tmp/imgui/dst/libimgui-java64.dylib /tmp/imgui/libsNative/macosx64/libimgui-java64.dylib /tmp/imgui/libsNative/macosxarm64/libimgui-java64.dylib + if [ $? -ne 0 ]; then + echo "Failed to create universal library with lipo" + exit 1 + fi + echo "Universal library created at /tmp/imgui/dst/libimgui-java64.dylib successfully" + ;; + *) + echo "Unknown vendor type: $VTYPE" + exit 1 + ;; +esac + +echo "Script completed successfully." diff --git a/buildSrc/scripts/publish.sh b/buildSrc/scripts/publish.sh index 72679f4..d744408 100644 --- a/buildSrc/scripts/publish.sh +++ b/buildSrc/scripts/publish.sh @@ -1,30 +1,45 @@ #!/bin/bash +# Set base directory and navigate to project root +echo "Setting base directory and navigating to project root..." BASEDIR=$(dirname "$0") -cd $BASEDIR/../.. || exit +cd "$BASEDIR"/../.. || exit 1 +echo "Navigated to $(pwd)" echo '> Publishing Modules...' -echo '>> Module [imgui-app]' -./gradlew imgui-app:publishImguiPublicationToMavenCentralRepository -echo '>> Module [imgui-lwjgl3]' -./gradlew imgui-lwjgl3:publishImguiPublicationToMavenCentralRepository -echo '>> Module [imgui-binding]' -./gradlew imgui-binding:publishImguiPublicationToMavenCentralRepository + +publish_module() { + local module=$1 + echo ">> Publishing Module [$module]" + ./gradlew $module:publishImguiPublicationToMavenCentralRepository + if [ $? -ne 0 ]; then + echo "Failed to publish $module module" + exit 1 + fi + echo ">> Module [$module] published successfully" +} + +# Publish each module +publish_module "imgui-app" +publish_module "imgui-lwjgl3" +publish_module "imgui-binding" echo '> Publishing Natives...' -echo '>> Natives: [windows, freetype]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=windows -Pfreetype=true -echo '>> Natives: [windows]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=windows -Pfreetype=false -echo '>> Natives: [linux, freetype]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=linux -Pfreetype=true -echo '>> Natives: [linux]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=linux -Pfreetype=false -echo '>> Natives: [macOS, freetype]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=macos -Pfreetype=true -echo '>> Natives: [macOS]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=macos -Pfreetype=false -echo '>> Natives: [macOS-arm64, freetype]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=macosarm64 -Pfreetype=true -echo '>> Natives: [macOS-arm64]' -./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=macosarm64 -Pfreetype=false + +publish_natives() { + local platform=$1 + echo ">> Publishing Natives: [$platform]" + ./gradlew imgui-binding-natives:publishImguiPublicationToMavenCentralRepository -PdeployType=$platform + if [ $? -ne 0 ]; then + echo "Failed to publish natives for $platform" + exit 1 + fi + echo ">> Natives for $platform published successfully" +} + +# Publish natives for each platform +publish_natives "windows" +publish_natives "linux" +publish_natives "macos" + +echo "All modules and natives published successfully." diff --git a/buildSrc/scripts/vendor_freetype.sh b/buildSrc/scripts/vendor_freetype.sh new file mode 100755 index 0000000..eecb26b --- /dev/null +++ b/buildSrc/scripts/vendor_freetype.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +# Set base directory and navigate to project root +echo "Setting base directory and navigating to project root..." +BASEDIR=$(dirname "$0") +cd "$BASEDIR"/../.. || exit 1 +echo "Navigated to $(pwd)" + +# Check if vendor type argument is provided +if [ -z "$1" ]; then + echo "Vendor type is required" + exit 1 +fi + +VTYPE=$1 +echo "Vendor type set to '$VTYPE'" + +# Define library directory and version +LIBDIR=build/vendor/freetype +VERSION=2.12.1 + +# Clean and create library directory, then extract FreeType source +echo "Cleaning and creating library directory, then extracting FreeType source..." +rm -rf $LIBDIR +mkdir -p $LIBDIR +tar -xzf ./vendor/freetype-$VERSION.tar.gz -C $LIBDIR --strip-components=1 +if [ $? -ne 0 ]; then + echo "Failed to extract FreeType source" + exit 1 +fi +cd $LIBDIR || exit 1 +echo "FreeType unzipped to $LIBDIR" + +# Common configuration flags +COMMON_FLAGS="--enable-static --disable-shared --without-zlib --without-bzip2 --without-png --without-harfbuzz --without-brotli" + +# Function to configure and build FreeType +build_freetype() { + cflags=$1 + prefix=$2 + output_dir=$3 + + echo "Cleaning previous builds..." + make clean + + echo "Configuring FreeType with CFLAGS='$cflags' and PREFIX='$prefix'..." + ./configure CFLAGS="$cflags" $COMMON_FLAGS $prefix + if [ $? -ne 0 ]; then + echo "Failed to configure FreeType" + exit 1 + fi + + echo "Building FreeType..." + make + if [ $? -ne 0 ]; then + echo "Failed to build FreeType" + exit 1 + fi + + echo "Checking if the generated library exists..." + if [ ! -f objs/.libs/libfreetype.a ]; then + echo "File objs/.libs/libfreetype.a not found!" + exit 1 + fi + + echo "Copying the generated library to $output_dir..." + cp objs/.libs/libfreetype.a "$output_dir" + if [ $? -ne 0 ]; then + echo "Failed to copy library to $output_dir" + exit 1 + fi + echo "Library copied to $output_dir" +} + +# Ensure necessary directories exist +echo "Ensuring necessary directories exist..." +mkdir -p lib tmp + +# Determine build process based on vendor type +case "$VTYPE" in + windows) + build_freetype "" "--host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32" "lib/libfreetype.a" + ;; + linux) + build_freetype "-fPIC" "" "lib/libfreetype.a" + ;; + macos) + MACOS_VERSION=10.15 + + build_freetype "-arch x86_64 -mmacosx-version-min=$MACOS_VERSION" "" "tmp/libfreetype-x86_64.a" + build_freetype "-arch arm64 -mmacosx-version-min=$MACOS_VERSION" "" "tmp/libfreetype-arm64.a" + + echo "Creating universal library using lipo..." + lipo -create -output lib/libfreetype.a tmp/libfreetype-x86_64.a tmp/libfreetype-arm64.a + if [ $? -ne 0 ]; then + echo "Failed to create universal library with lipo" + exit 1 + fi + echo "Universal library created at lib/libfreetype.a" + ;; + *) + echo "Unknown vendor type: $VTYPE" + exit 1 + ;; +esac + +echo "Script completed successfully." diff --git a/buildSrc/src/main/groovy/tool/generator/GenerateLibs.groovy b/buildSrc/src/main/groovy/tool/generator/GenerateLibs.groovy index 972263f..b0aabf4 100644 --- a/buildSrc/src/main/groovy/tool/generator/GenerateLibs.groovy +++ b/buildSrc/src/main/groovy/tool/generator/GenerateLibs.groovy @@ -10,6 +10,18 @@ import org.gradle.api.tasks.TaskAction @CompileStatic class GenerateLibs extends DefaultTask { + private static final String[] INCLUDES = [ + 'include/imgui', + 'include/imnodes', + 'include/imgui-node-editor', + 'include/imguizmo', + 'include/implot', + 'include/ImGuiColorTextEdit', + 'include/ImGuiFileDialog', + 'include/imgui_club/imgui_memory_editor', + 'include/imgui-knobs' + ] + @Internal String group = 'build' @Internal @@ -26,9 +38,10 @@ class GenerateLibs extends DefaultTask { private final String sourceDir = project.file('src/main/java') private final String classpath = project.file('build/classes/java/main') - private final String jniDir = (isLocal ? project.buildDir.path : '/tmp/imgui') + '/jni' - private final String tmpFolder = (isLocal ? project.buildDir.path : '/tmp/imgui') + '/tmp' - private final String libsFolder = 'libsNative' + private final String rootDir = (isLocal ? project.buildDir.path : '/tmp/imgui') + private final String jniDir = "$rootDir/jni" + private final String tmpDir = "$rootDir/tmp" + private final String libsDirName = 'libsNative' @TaskAction void generate() { @@ -42,47 +55,46 @@ class GenerateLibs extends DefaultTask { throw new IllegalStateException('No build targets') } + new File(jniDir).deleteDir() + new File(tmpDir).deleteDir() + new File("$rootDir/$libsDirName").deleteDir() + // Generate h/cpp files for JNI new NativeCodeGenerator().generate(sourceDir, classpath, jniDir) // Copy ImGui h/cpp files project.copy { CopySpec spec -> - ['include/imgui', 'include/imnodes', 'include/imgui-node-editor', - 'include/imguizmo', 'include/implot', 'include/ImGuiColorTextEdit', - 'include/ImGuiFileDialog', 'include/imgui_club/imgui_memory_editor', 'include/imgui-knobs'].each { + INCLUDES.each { spec.from(project.rootProject.file(it)) { CopySpec s -> s.include('*.h', '*.cpp', '*.inl') } } spec.from(project.rootProject.file('imgui-binding/src/main/native')) spec.into(jniDir) - spec.duplicatesStrategy = DuplicatesStrategy.INCLUDE //Allows for duplicate imconfig.h, we ensure the correct one is copied below + spec.duplicatesStrategy = DuplicatesStrategy.INCLUDE // Allows for duplicate imconfig.h, we ensure the correct one is copied below } - //Ensure we overwrite imconfig.h with our own + // Ensure we overwrite imconfig.h with our own project.copy { CopySpec spec -> spec.from(project.rootProject.file('imgui-binding/src/main/native/imconfig.h')) spec.into(jniDir) } - //Copy dirent for ImGuiFileDialog - project.copy { CopySpec spec -> - ['include/ImGuiFileDialog/dirent'].each { - spec.from(project.rootProject.file(it)) { CopySpec s -> s.include('*.h', '*.cpp', '*.inl') } - } - spec.into(jniDir + '/dirent') - } - if (withFreeType) { project.copy { CopySpec spec -> spec.from(project.rootProject.file('include/imgui/misc/freetype')) { CopySpec it -> it.include('*.h', '*.cpp') } spec.into("$jniDir/misc/freetype") } - enableDefine('IMGUI_ENABLE_FREETYPE') } + // Copy dirent for ImGuiFileDialog + project.copy { CopySpec spec -> + spec.from(project.rootProject.file('include/ImGuiFileDialog/dirent')) { CopySpec s -> s.include('*.h', '*.cpp', '*.inl') } + spec.into(jniDir + '/dirent') + } + // Generate platform dependant ant configs and header files - def buildConfig = new BuildConfig('imgui-java', tmpFolder, libsFolder, jniDir) - def buildTargets = [] as BuildTarget[] + def buildConfig = new BuildConfig('imgui-java', tmpDir, libsDirName, jniDir) + BuildTarget[] buildTargets = [] if (forWindows) { def win64 = BuildTarget.newDefaultTarget(BuildTarget.TargetOs.Windows, true) @@ -97,23 +109,11 @@ class GenerateLibs extends DefaultTask { } if (forMac) { - def minMacOsVersion = '10.15' - def mac64 = BuildTarget.newDefaultTarget(BuildTarget.TargetOs.MacOsX, true) - mac64.cppFlags += ' -std=c++14' - mac64.cppFlags = mac64.cppFlags.replace('10.7', minMacOsVersion) - mac64.linkerFlags = mac64.linkerFlags.replace('10.7', minMacOsVersion) - addFreeTypeIfEnabled(mac64) - buildTargets += mac64 + buildTargets += createMacTarget(false) } if (forMacArm64) { - def minMacOsVersion = '10.15' - def macArm64 = BuildTarget.newDefaultTarget(BuildTarget.TargetOs.MacOsX, true, true) - macArm64.cppFlags += ' -std=c++14' - macArm64.cppFlags = macArm64.cppFlags.replace('10.7', minMacOsVersion) - macArm64.linkerFlags = macArm64.linkerFlags.replace('10.7', minMacOsVersion) - addFreeTypeIfEnabled(macArm64) - buildTargets += macArm64 + buildTargets += createMacTarget(true) } new AntScriptGenerator().generate(buildConfig, buildTargets) @@ -133,6 +133,34 @@ class GenerateLibs extends DefaultTask { BuildExecutor.executeAnt(jniDir + '/build-macosxarm64.xml', commonParams) BuildExecutor.executeAnt(jniDir + '/build.xml', '-v', 'pack-natives') + + if (forWindows) + checkLibExist("windows64/imgui-java64.dll") + if (forLinux) + checkLibExist("linux64/libimgui-java64.so") + if (forMac) + checkLibExist("macosx64/libimgui-java64.dylib") + if (forMacArm64) + checkLibExist("macosxarm64/libimgui-java64.dylib") + } + + void checkLibExist(String libName) { + def path = new File("$rootDir/$libsDirName/$libName") + if (!path.exists()) { + logger.error("Failed to build $libName!") + throw new IllegalStateException("$path does not exist") + } + } + + BuildTarget createMacTarget(Boolean isArm) { + def minMacOsVersion = '10.15' + def macTarget = BuildTarget.newDefaultTarget(BuildTarget.TargetOs.MacOsX, true, isArm) + macTarget.libName = "libimgui-java64.dylib" // Lib for arm64 will be named the same for consistency. + macTarget.cppFlags += ' -std=c++14' + macTarget.cppFlags = macTarget.cppFlags.replace('10.7', minMacOsVersion) + macTarget.linkerFlags = macTarget.linkerFlags.replace('10.7', minMacOsVersion) + addFreeTypeIfEnabled(macTarget) + return macTarget } void addFreeTypeIfEnabled(BuildTarget target) { @@ -140,22 +168,18 @@ class GenerateLibs extends DefaultTask { return } - switch (target.os) { - case BuildTarget.TargetOs.Windows: - target.cppFlags += ' -I/usr/x86_64-w64-mingw32/include/freetype2' - break - case BuildTarget.TargetOs.Linux: - target.cppFlags += ' -I/usr/include/freetype2' - break - case BuildTarget.TargetOs.MacOsX: - target.cppFlags += ' -I/usr/local/include/freetype2' - break + def freetypeVendorDir = project.rootProject.file('build/vendor/freetype') + if (!freetypeVendorDir.exists()) { + logger.error("$freetypeVendorDir doesn't exist! Run 'buildSrc/scripts/vendor_freetype.sh' for your platform beforehand!") + throw new IllegalStateException("Unable to build library for FreeType") } + target.cppFlags += " -I$freetypeVendorDir/include" + target.linkerFlags += " -L${project.rootProject.file("$freetypeVendorDir/lib")}" target.libraries += ' -lfreetype' } void enableDefine(String define) { - project.file("$jniDir/imconfig.h").text += "#define $define" + new File("$jniDir/imconfig.h").text += "#define $define" } } diff --git a/example/src/main/java/Main.java b/example/src/main/java/Main.java index 907f7dd..d70f5a8 100644 --- a/example/src/main/java/Main.java +++ b/example/src/main/java/Main.java @@ -72,6 +72,7 @@ public class Main extends Application { @Override public void process() { if (ImGui.begin("Demo", ImGuiWindowFlags.AlwaysAutoResize)) { + ImGui.text("OS: [" + System.getProperty("os.name") + "] Arch: [" + System.getProperty("os.arch") + "]"); ImGui.text("Hello, World! " + FontAwesomeIcons.Smile); if (ImGui.button(FontAwesomeIcons.Save + " Save")) { count++; diff --git a/imgui-app/build.gradle b/imgui-app/build.gradle index 0e630b7..0e2368d 100644 --- a/imgui-app/build.gradle +++ b/imgui-app/build.gradle @@ -31,13 +31,9 @@ dependencies { jar { from('../bin') { + include 'imgui-java64.dll' include 'libimgui-java64.so' include 'libimgui-java64.dylib' - include 'libimgui-javaarm64.dylib' - into 'io/imgui/java/native-bin/' - } - from('../bin/freetype') { - include 'imgui-java64.dll' into 'io/imgui/java/native-bin/' } manifest { diff --git a/imgui-binding-natives/build.gradle b/imgui-binding-natives/build.gradle index 7e690a8..27c79d1 100644 --- a/imgui-binding-natives/build.gradle +++ b/imgui-binding-natives/build.gradle @@ -31,22 +31,10 @@ switch (findProperty('deployType')) { break case 'macos': packageName = 'imgui-java-natives-macos' - packageDesc = 'Native binaries for imgui-java binding for MacOS' + packageDesc = 'Native binaries for imgui-java binding for macOS' moduleName = 'imgui.natives.macos' libName = 'libimgui-java64.dylib' break - case 'macosarm64': - packageName = 'imgui-java-natives-macos-arm64' - packageDesc = 'Native binaries for imgui-java binding for MacOS arm64' - moduleName = 'imgui.natives.macos-arm64' - libName = 'libimgui-javaarm64.dylib' - break -} - -if (findProperty('freetype') == 'true') { - packageName += '-ft' - packageDesc += ' with Freetype support' - fromDir += '/freetype' } jar { diff --git a/imgui-binding/src/main/java/imgui/ImGui.java b/imgui-binding/src/main/java/imgui/ImGui.java index 13b1288..20b0312 100644 --- a/imgui-binding/src/main/java/imgui/ImGui.java +++ b/imgui-binding/src/main/java/imgui/ImGui.java @@ -29,8 +29,7 @@ import java.util.Properties; public class ImGui { private static final String LIB_PATH_PROP = "imgui.library.path"; private static final String LIB_NAME_PROP = "imgui.library.name"; - private static final boolean isARM = System.getProperty("os.arch").equals("arm") || System.getProperty("os.arch").startsWith("aarch64"); - private static final String LIB_NAME_DEFAULT = "imgui-java" + (isARM ? "arm" : "") + "64"; + private static final String LIB_NAME_DEFAULT = "imgui-java64"; private static final String LIB_TMP_DIR_PREFIX = "imgui-java-natives"; private static final ImGuiContext IMGUI_CONTEXT;