diff --git a/.github/workflows/spine-godot-extension-v4-all.yml b/.github/workflows/spine-godot-extension-v4-all.yml new file mode 100644 index 000000000..5eab10096 --- /dev/null +++ b/.github/workflows/spine-godot-extension-v4-all.yml @@ -0,0 +1,25 @@ +name: Build spine-godot GDExtension (All Godot 4.x versions) + +on: + push: + paths: + - ".github/workflows/spine-godot.yml" + - 'spine-godot/**' + - 'spine-cpp/**' + workflow_dispatch: + +jobs: + build-versions: + strategy: + matrix: + version: + [ + {"tag": "4.3-stable", "version": "4.3.stable", "dev": false}, + {"tag": "4.2.2-stable", "version": "4.2.2.stable", "dev": false}, + ] + uses: ./.github/workflows/spine-godot-extension-v4.yml + with: + godot_tag: ${{ matrix.version.tag }} + godot_version: ${{ matrix.version.version }} + dev: ${{ matrix.version.dev }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/spine-godot-extension-v4.yml b/.github/workflows/spine-godot-extension-v4.yml new file mode 100644 index 000000000..1b73e1309 --- /dev/null +++ b/.github/workflows/spine-godot-extension-v4.yml @@ -0,0 +1,281 @@ +name: Build spine-godot GDExtension (Godot 4.x) + +on: + workflow_call: + inputs: + godot_tag: + required: true + type: string + default: "Godot tag not specified!" + godot_version: + required: true + type: string + default: "Godot version not specified!" + dev: + required: true + type: boolean + default: false + +env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_EC2_METADATA_DISABLED: true + GODOT_TAG: ${{ inputs.godot_tag }} + GODOT_VERSION: ${{ inputs.godot_version }} + DEV_BUILD: ${{ inputs.dev }} + +jobs: + build-windows: + runs-on: windows-2022 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup python and scons + uses: ./.github/actions/setup-godot-deps-4 + + - name: Build GDExtension + shell: bash + run: | + ./setup-extension.sh $GODOT_TAG $DEV + ./build-extension.sh windows + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: gdextension-windows-${{ env.GODOT_TAG }} + path: example-v4-extension/bin/windows/*.dll + + build-linux-x86_64: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup python and scons + uses: ./.github/actions/setup-godot-deps-4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential scons pkg-config libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev + + - name: Build GDExtension + run: | + ./setup-extension.sh $GODOT_TAG $DEV + ./build-extension.sh linux + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: gdextension-linux-x86_64-${{ env.GODOT_TAG }} + path: example-v4-extension/bin/linux/*.so + + build-linux-arm64: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup python and scons + uses: ./.github/actions/setup-godot-deps-4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential scons pkg-config gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + + - name: Build GDExtension + run: | + ./setup-extension.sh $GODOT_TAG $DEV + ./build-extension.sh linux arm64 + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: gdextension-linux-arm64-${{ env.GODOT_TAG }} + path: example-v4-extension/bin/linux/*.so + + build-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup python and scons + uses: ./.github/actions/setup-godot-deps-4 + + - name: Build GDExtension + run: | + ./setup-extension.sh $GODOT_TAG $DEV + ./build-extension.sh macos + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: gdextension-macos-${{ env.GODOT_TAG }} + path: example-v4-extension/bin/macos/macos.framework/* + + build-ios: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup python and scons + uses: ./.github/actions/setup-godot-deps-4 + + - name: Build GDExtension + run: | + ./setup-extension.sh $GODOT_TAG $DEV + ./build-extension.sh ios + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: gdextension-ios-${{ env.GODOT_TAG }} + path: example-v4-extension/bin/ios/*.xcframework/**/* + + build-android: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Make apt sources.list use the default Ubuntu repositories + run: | + sudo rm -f /etc/apt/sources.list.d/* + sudo cp -f build/sources.lst /etc/apt/sources.list + sudo apt-get update + + - name: Set up Java 17 + uses: actions/setup-java@v1 + with: + java-version: 17 + + - name: Setup python and scons + uses: ./.github/actions/setup-godot-deps-4 + + - name: Build GDExtension + run: | + ./setup-extension.sh $GODOT_TAG $DEV + ./build-extension.sh android + ./build-extension.sh android x86_64 + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: gdextension-android-${{ env.GODOT_TAG }} + path: example-v4-extension/bin/android/*.so + + build-web: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Emscripten latest + uses: mymindstorm/setup-emsdk@v11 + with: + version: 3.1.26 + + - name: Setup python and scons + uses: ./.github/actions/setup-godot-deps-4 + + - name: Build GDExtension + run: | + ./setup-extension.sh $GODOT_TAG $DEV + ./build-extension.sh web + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: gdextension-web-${{ env.GODOT_TAG }} + path: example-v4-extension/bin/web/*.wasm + + upload-to-s3: + needs: [build-windows, build-linux-x86_64, build-linux-arm64, build-macos, build-ios, build-android, build-web] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Download windows artifact + uses: actions/download-artifact@v4 + with: + name: gdextension-windows-${{ env.GODOT_TAG }} + path: artifacts/gdextension-windows-${{ env.GODOT_TAG }} + + - name: Download linux-x86_64 artifact + uses: actions/download-artifact@v4 + with: + name: gdextension-linux-x86_64-${{ env.GODOT_TAG }} + path: artifacts/gdextension-linux-x86_64-${{ env.GODOT_TAG }} + + - name: Download linux-arm64 artifact + uses: actions/download-artifact@v4 + with: + name: gdextension-linux-arm64-${{ env.GODOT_TAG }} + path: artifacts/gdextension-linux-arm64-${{ env.GODOT_TAG }} + + - name: Download macos artifact + uses: actions/download-artifact@v4 + with: + name: gdextension-macos-${{ env.GODOT_TAG }} + path: artifacts/gdextension-macos-${{ env.GODOT_TAG }} + + - name: Download ios artifact + uses: actions/download-artifact@v4 + with: + name: gdextension-ios-${{ env.GODOT_TAG }} + path: artifacts/gdextension-ios-${{ env.GODOT_TAG }} + + - name: Download android artifact + uses: actions/download-artifact@v4 + with: + name: gdextension-android-${{ env.GODOT_TAG }} + path: artifacts/gdextension-android-${{ env.GODOT_TAG }} + + - name: Download web artifact + uses: actions/download-artifact@v4 + with: + name: gdextension-web-${{ env.GODOT_TAG }} + path: artifacts/gdextension-web-${{ env.GODOT_TAG }} + + - name: Package and upload artifacts + shell: bash + if: env.AWS_ACCESS_KEY_ID != null + run: | + BRANCH=${GITHUB_REF#refs/heads/} + echo "branch: $BRANCH" + + cd artifacts + # Ensure gdextension file is in root + cp ../spine_godot_extension.gdextension ./ + + # Create directories matching the expected structure + mkdir -p bin/{windows,linux,macos/macos.framework,ios,android,web} + + # Move artifacts to their correct locations + mv gdextension-windows-$GODOT_TAG/* bin/windows/ + mv gdextension-linux-x86_64-$GODOT_TAG/* bin/linux/ + mv gdextension-linux-arm64-$GODOT_TAG/* bin/linux/ + mv gdextension-macos-$GODOT_TAG/* bin/macos/macos.framework/ + mv gdextension-ios-$GODOT_TAG/* bin/ios/ + mv gdextension-android-$GODOT_TAG/* bin/android/ + mv gdextension-web-$GODOT_TAG/* bin/web/ + + # Create the final zip with branch and tag + zip -r ../spine-godot-extension-$BRANCH-$GODOT_TAG.zip spine_godot_extension.gdextension bin/ + + cd .. + aws s3 cp spine-godot-extension-$BRANCH-$GODOT_TAG.zip s3://spine-godot/$BRANCH/$GODOT_TAG/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 35f2fd4f1..e31bd8d52 100644 --- a/.gitignore +++ b/.gitignore @@ -218,3 +218,4 @@ spine-godot/.idea spine-godot/build/version.txt spine-godot/vc140.pdb spine-godot/example-v4-extension/bin +spine-godot/example-v4-extension/MoltenVK.xcframework diff --git a/spine-godot/build/build-extension.sh b/spine-godot/build/build-extension.sh index 799c72a97..253064b74 100755 --- a/spine-godot/build/build-extension.sh +++ b/spine-godot/build/build-extension.sh @@ -5,53 +5,161 @@ dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" pushd "$dir" > /dev/null if [ ! -d ../godot-cpp ]; then - echo "No godot-cpp clone found. Run ./setup-extension.sh first." - exit 1 + echo "No godot-cpp clone found. Run ./setup-extension.sh first." + exit 1 fi options="" dev="false" -platform=${1%/} +raw_platform=${1%/} # Store the raw platform name before adding platform= +platform="platform=$raw_platform" # Add platform= prefix +arch=$2 if [ -f "../godot-cpp/dev" ]; then - dev="true" - echo "DEV build" + dev="true" + echo "DEV build" fi if [ $dev == "true" ]; then options="$options dev_build=true" fi -if [ -z $platform ]; then +if [ -z $raw_platform ]; then echo "Platform: current" + platform="" else - echo "Platform: $platform" - platform="platform=$platform" + echo "Platform: $raw_platform" +fi + +if [ ! -z "$arch" ]; then + echo "Architecture: $arch" + if [ "$raw_platform" == "linux" ] || [ "$raw_platform" == "android" ]; then + options="$options arch=$arch" + fi fi cpus=2 if [ "$OSTYPE" == "msys" ]; then - os="windows" - cpus=$NUMBER_OF_PROCESSORS + os="windows" + cpus=$NUMBER_OF_PROCESSORS elif [[ "$OSTYPE" == "darwin"* ]]; then - os="macos" - cpus=$(sysctl -n hw.logicalcpu) - if [ `uname -m` == "arm64" ]; then + os="macos" + cpus=$(sysctl -n hw.logicalcpu) + if [ `uname -m` == "arm64" ]; then echo "Would do Apple Silicon specific setup" - fi + fi else - os="linux" - cpus=$(grep -c ^processor /proc/cpuinfo) + os="linux" + cpus=$(grep -c ^processor /proc/cpuinfo) fi echo "CPUS: $cpus" pushd .. -if [ "$platform" != "ios" ] && [ "$platform" != "android" ] && [ "$platform" != "web" ]; then - scons -j $cpus $options $platform target=editor + +if [ "$raw_platform" == "ios" ]; then + BINDIR="example-v4-extension/bin/ios" + mkdir -p $BINDIR + + # Step 1: Build simulator binaries + echo "Building for iOS simulator..." + scons -j $cpus $options $platform target=template_debug arch=universal ios_simulator=yes + mv $BINDIR/ios.framework/libspine_godot.ios.template_debug $BINDIR/libspine_godot.ios.template_debug.simulator.a + + scons -j $cpus $options $platform target=template_release arch=universal ios_simulator=yes + mv $BINDIR/ios.framework/libspine_godot.ios.template_release $BINDIR/libspine_godot.ios.template_release.simulator.a + + # Step 2: Build device binaries + echo "Building for iOS device..." + scons -j $cpus $options $platform target=template_debug arch=arm64 ios_simulator=no + mv $BINDIR/ios.framework/libspine_godot.ios.template_debug $BINDIR/libspine_godot.ios.template_debug.a + + scons -j $cpus $options $platform target=template_release arch=arm64 ios_simulator=no + mv $BINDIR/ios.framework/libspine_godot.ios.template_release $BINDIR/libspine_godot.ios.template_release.a + + # Step 3: Create xcframeworks + echo "Creating xcframeworks..." + + xcodebuild -create-xcframework \ + -library $BINDIR/libspine_godot.ios.template_debug.a \ + -library $BINDIR/libspine_godot.ios.template_debug.simulator.a \ + -output $BINDIR/libspine_godot.ios.template_debug.xcframework + + xcodebuild -create-xcframework \ + -library $BINDIR/libspine_godot.ios.template_release.a \ + -library $BINDIR/libspine_godot.ios.template_release.simulator.a \ + -output $BINDIR/libspine_godot.ios.template_release.xcframework + + # Cleanup intermediate files + rm -f $BINDIR/*.a + rm -rf $BINDIR/ios.framework + +elif [ "$raw_platform" == "macos" ]; then + BINDIR="example-v4-extension/bin/macos/macos.framework" + TMPDIR="example-v4-extension/bin/macos/tmp" + mkdir -p $BINDIR $TMPDIR + + # Build x86_64 binaries + echo "Building for macOS x86_64..." + scons -j $cpus $options $platform target=editor arch=x86_64 + mv $BINDIR/libspine_godot.macos.editor $TMPDIR/libspine_godot.macos.editor.x86_64 + scons -j $cpus $options $platform target=template_debug arch=x86_64 + mv $BINDIR/libspine_godot.macos.template_debug $TMPDIR/libspine_godot.macos.template_debug.x86_64 + scons -j $cpus $options $platform target=template_release arch=x86_64 + mv $BINDIR/libspine_godot.macos.template_release $TMPDIR/libspine_godot.macos.template_release.x86_64 + + # Build arm64 binaries + echo "Building for macOS arm64..." + scons -j $cpus $options $platform target=editor arch=arm64 + mv $BINDIR/libspine_godot.macos.editor $TMPDIR/libspine_godot.macos.editor.arm64 + scons -j $cpus $options $platform target=template_debug arch=arm64 + mv $BINDIR/libspine_godot.macos.template_debug $TMPDIR/libspine_godot.macos.template_debug.arm64 + scons -j $cpus $options $platform target=template_release arch=arm64 + mv $BINDIR/libspine_godot.macos.template_release $TMPDIR/libspine_godot.macos.template_release.arm64 + + # Create universal binaries + echo "Creating universal binaries..." + lipo -create \ + $TMPDIR/libspine_godot.macos.editor.x86_64 \ + $TMPDIR/libspine_godot.macos.editor.arm64 \ + -output $BINDIR/libspine_godot.macos.editor + + lipo -create \ + $TMPDIR/libspine_godot.macos.template_debug.x86_64 \ + $TMPDIR/libspine_godot.macos.template_debug.arm64 \ + -output $BINDIR/libspine_godot.macos.template_debug + + lipo -create \ + $TMPDIR/libspine_godot.macos.template_release.x86_64 \ + $TMPDIR/libspine_godot.macos.template_release.arm64 \ + -output $BINDIR/libspine_godot.macos.template_release + + # Cleanup intermediate files + rm -rf $TMPDIR + +elif [ "$raw_platform" == "web" ]; then + BINDIR="example-v4-extension/bin/web" + mkdir -p $BINDIR + + # Build threaded versions + echo "Building web with threads..." + scons -j $cpus $options $platform target=template_debug + scons -j $cpus $options $platform target=template_release + + # Build non-threaded versions + echo "Building web without threads..." + scons -j $cpus $options $platform target=template_debug threads=no + scons -j $cpus $options $platform target=template_release threads=no + +else + # Normal build process for other platforms + if [ "$raw_platform" != "android" ] && [ "$raw_platform" != "web" ]; then + scons -j $cpus $options $platform target=editor + fi + scons -j $cpus $options $platform target=template_debug + scons -j $cpus $options $platform target=template_release fi -scons -j $cpus $options $platform target=template_debug -scons -j $cpus $options $platform target=template_release + popd popd \ No newline at end of file diff --git a/spine-godot/example-v4-extension/project.godot b/spine-godot/example-v4-extension/project.godot index 26b85fd71..a6ec80c2a 100644 --- a/spine-godot/example-v4-extension/project.godot +++ b/spine-godot/example-v4-extension/project.godot @@ -26,6 +26,7 @@ common/enable_pause_aware_picking=true [rendering] +textures/vram_compression/import_etc2_astc=true batching/parameters/max_join_item_commands=100 batching/parameters/batch_buffer_size=65535 batching/parameters/item_reordering_lookahead=100 diff --git a/spine-godot/spine_godot_extension.gdextension b/spine-godot/spine_godot_extension.gdextension index c100cb488..8b263ce23 100644 --- a/spine-godot/spine_godot_extension.gdextension +++ b/spine-godot/spine_godot_extension.gdextension @@ -9,8 +9,8 @@ macos.editor = "res://bin/macos/macos.framework/libspine_godot.macos.editor" macos.debug = "res://bin/macos/macos.framework/libspine_godot.macos.template_debug" macos.release = "res://bin/macos/macos.framework/libspine_godot.macos.template_release" -ios.debug = "res://bin/ios/ios.framework/libspine_godot.ios.template_debug" -ios.release = "res://bin/ios/ios.framework/libspine_godot.ios.template_release" +ios.debug = "res://bin/ios/ios.framework/libspine_godot.ios.template_debug.xcframework" +ios.release = "res://bin/ios/ios.framework/libspine_godot.ios.template_release.xcframework" windows.editor.x86_64 = "res://bin/windows/libspine_godot.windows.editor.x86_64.dll" windows.debug.x86_64 = "res://bin/windows/libspine_godot.windows.template_debug.x86_64.dll" @@ -32,4 +32,9 @@ android.debug.x86_64 = "res://bin/android/libspine_godot.android.template_debug. android.release.x86_64 = "res://bin/android/libspine_godot.android.template_release.x86_64.so" android.debug.arm64 = "res://bin/android/libspine_godot.android.template_debug.arm64.so" -android.release.arm64 = "res://bin/android/libspine_godot.android.template_release.arm64.so" \ No newline at end of file +android.release.arm64 = "res://bin/android/libspine_godot.android.template_release.arm64.so" + +web.debug.threads.wasm32 = "res://bin/web/libgdexample.web.template_debug.wasm32.wasm" +web.release.threads.wasm32 = "res://bin/web/libgdexample.web.template_release.wasm32.wasm" +web.debug.wasm32 = "res://bin/web/libgdexample.web.template_debug.wasm32.nothreads.wasm" +web.release.wasm32 = "res://bin/web/libgdexample.web.template_release.wasm32.nothreads.wasm" \ No newline at end of file diff --git a/spine-godot/webserver.py b/spine-godot/webserver.py new file mode 100644 index 000000000..7e6399c4a --- /dev/null +++ b/spine-godot/webserver.py @@ -0,0 +1,42 @@ +from http.server import HTTPServer, SimpleHTTPRequestHandler +import os +import sys +import argparse + +class GodotWebServer(SimpleHTTPRequestHandler): + def end_headers(self): + self.send_header('Cross-Origin-Opener-Policy', 'same-origin') + self.send_header('Cross-Origin-Embedder-Policy', 'require-corp') + super().end_headers() + +def run_server(directory='.', port=8000): + os.chdir(directory) + + server_address = ('', port) + httpd = HTTPServer(server_address, GodotWebServer) + print(f'Serving directory: {os.path.abspath(directory)}') + print(f'Server running at http://localhost:{port}/') + try: + httpd.serve_forever() + except KeyboardInterrupt: + print('\nShutting down server...') + httpd.server_close() + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Start a web server for Godot exports') + parser.add_argument('path', nargs='?', default='.', + help='Path to the directory to serve (default: current directory)') + parser.add_argument('--port', '-p', type=int, default=8000, + help='Port to run the server on (default: 8000)') + + args = parser.parse_args() + + if not os.path.exists(args.path): + print(f"Error: Directory '{args.path}' does not exist") + sys.exit(1) + + if not os.path.isdir(args.path): + print(f"Error: '{args.path}' is not a directory") + sys.exit(1) + + run_server(args.path, args.port) \ No newline at end of file