From 1886723da250595b0dcaabf08977fdbfc3ea7328 Mon Sep 17 00:00:00 2001
From: Blitz <>
Date: Sun, 11 Aug 2024 18:55:31 +0200
Subject: [PATCH] Initial commit
---
.gitattributes | 3 +
.gitea/workflows/linux.yml | 32 +++
.gitignore | 20 ++
LICENSE | 21 ++
README.md | 62 ++++++
demo/export_presets.cfg | 410 +++++++++++++++++++++++++++++++++++++
demo/icon.svg | 1 +
demo/icon.svg.import | 37 ++++
demo/main.tscn | 10 +
demo/project.godot | 16 ++
src/gdexample.cpp | 28 +++
src/gdexample.h | 24 +++
src/register_types.cpp | 44 ++++
src/register_types.h | 11 +
templates/class_tpl.lua | 103 ++++++++++
xmake.lua | 21 ++
xmake/editor.lua | 15 ++
xmake/godot.lua | 26 +++
xmake/target.lua | 65 ++++++
xmake/tasks.lua | 204 ++++++++++++++++++
20 files changed, 1153 insertions(+)
create mode 100644 .gitattributes
create mode 100644 .gitea/workflows/linux.yml
create mode 100644 .gitignore
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 demo/export_presets.cfg
create mode 100644 demo/icon.svg
create mode 100644 demo/icon.svg.import
create mode 100644 demo/main.tscn
create mode 100644 demo/project.godot
create mode 100644 src/gdexample.cpp
create mode 100644 src/gdexample.h
create mode 100644 src/register_types.cpp
create mode 100644 src/register_types.h
create mode 100644 templates/class_tpl.lua
create mode 100644 xmake.lua
create mode 100644 xmake/editor.lua
create mode 100644 xmake/godot.lua
create mode 100644 xmake/target.lua
create mode 100644 xmake/tasks.lua
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..4ee53b0
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,3 @@
+*.zip filter=lfs diff=lfs merge=lfs -text
+*.png filter=lfs diff=lfs merge=lfs -text
+*.fbx filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitea/workflows/linux.yml b/.gitea/workflows/linux.yml
new file mode 100644
index 0000000..643d2c5
--- /dev/null
+++ b/.gitea/workflows/linux.yml
@@ -0,0 +1,32 @@
+name: Linux arm64
+run-name: Build And Test
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ Build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out repository code
+ uses: actions/checkout@v3
+
+ - name: Packages cache
+ uses: actions/cache@v4
+ with:
+ path: ${{ github.workspace }}/build/.packages
+ key: ${{ runner.os }}-xmake_cache
+
+ - name: XMake config
+ run: xmake f -p linux -y
+
+ - name: Build
+ run: xmake
+
+ - name: Test
+ run: xmake test
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2797204
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+# Xmake cache
+.xmake/
+build/
+
+# MacOS Cache
+.DS_Store
+
+.vscode/
+
+*.dll
+*.exp
+*.pdb
+*.ilk
+*.obj
+*.lib
+*.TMP
+
+demo/.godot
+
+publish
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..436dd8e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Simon Pribylski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..eabe994
--- /dev/null
+++ b/README.md
@@ -0,0 +1,62 @@
+
+This project is used to compile a GDExtension (godot engine cpp extension), and try to use xmake to manage the project.
+
+Forked from [Github](https://github.com/chaosddp/gdextension-cpp-xmake-template)
+
+## Install xmake
+
+Install xmake from [here](https://xmake.io/#/guide/installation).
+
+## How to use
+
+You must have godot in your path
+
+First modify the *xmake.lua* to change the project name, and other configurations as needed.
+
+```lua
+
+-- project name, this will be the output shared library name
+PROJECT_NAME = "gdexample"
+
+-- project version
+VERSION = "0.0.1"
+
+-- where is the godot project saved, default is "demo"
+GODOT_PROJECT_FOLDER = "demo"
+
+-- where to save the export project, default is "publish"
+PUBLISH_FOLDER = "publish"
+
+```
+
+After change the configurations, you can run the following commands to build, run and export.
+
+```sh
+
+# 1. gen gdextension file (only once)
+xmake gengdextension
+
+# 2. build the project
+xmake
+
+# 3. open the editor at least once (works only in debug mode)
+xmake run Editor
+
+# 4. run the demo (works only in debug mode)
+xmake run
+
+# 5. export the project, the executable will be under "publish" folder by default
+xmake p
+
+# 6. clean the build and publish
+xmake clean
+
+# 7. generate a class that inherits from godot class, like Sprite2D
+# by default the generated files will save under "src" folder, you can change it by -d folder/under/src
+xmake ext-class -n MySprite2D -b Sprite2D -s myexample1 -d sample
+
+```
+
+For better support in vscode, you can use command "Xmake: UpdateIntellisense" to generate *compile_commands.json*, then update "compileCommands" field in *c_cpp_properties.json* to point to the file.
+
+NOTE: not tested on other platforms except windows and linux.
\ No newline at end of file
diff --git a/demo/export_presets.cfg b/demo/export_presets.cfg
new file mode 100644
index 0000000..85165a6
--- /dev/null
+++ b/demo/export_presets.cfg
@@ -0,0 +1,410 @@
+[preset.0]
+
+name="Windows Desktop"
+platform="Windows Desktop"
+runnable=true
+dedicated_server=false
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path=""
+encryption_include_filters=""
+encryption_exclude_filters=""
+encrypt_pck=false
+encrypt_directory=false
+
+[preset.0.options]
+
+custom_template/debug=""
+custom_template/release=""
+debug/export_console_wrapper=1
+binary_format/embed_pck=false
+texture_format/bptc=true
+texture_format/s3tc=true
+texture_format/etc=false
+texture_format/etc2=false
+binary_format/architecture="x86_64"
+codesign/enable=false
+codesign/timestamp=true
+codesign/timestamp_server_url=""
+codesign/digest_algorithm=1
+codesign/description=""
+codesign/custom_options=PackedStringArray()
+application/modify_resources=true
+application/icon=""
+application/console_wrapper_icon=""
+application/icon_interpolation=4
+application/file_version=""
+application/product_version=""
+application/company_name=""
+application/product_name=""
+application/file_description=""
+application/copyright=""
+application/trademarks=""
+application/export_angle=0
+ssh_remote_deploy/enabled=false
+ssh_remote_deploy/host="user@host_ip"
+ssh_remote_deploy/port="22"
+ssh_remote_deploy/extra_args_ssh=""
+ssh_remote_deploy/extra_args_scp=""
+ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
+$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
+$trigger = New-ScheduledTaskTrigger -Once -At 00:00
+$settings = New-ScheduledTaskSettingsSet
+$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
+Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
+Start-ScheduledTask -TaskName godot_remote_debug
+while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
+Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
+ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
+Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
+Remove-Item -Recurse -Force '{temp_dir}'"
+
+[preset.1]
+
+name="Linux/X11"
+platform="Linux/X11"
+runnable=true
+dedicated_server=false
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path=""
+encryption_include_filters=""
+encryption_exclude_filters=""
+encrypt_pck=false
+encrypt_directory=false
+
+[preset.1.options]
+
+custom_template/debug=""
+custom_template/release=""
+debug/export_console_wrapper=1
+binary_format/embed_pck=false
+texture_format/bptc=true
+texture_format/s3tc=true
+texture_format/etc=false
+texture_format/etc2=false
+binary_format/architecture="x86_64"
+ssh_remote_deploy/enabled=false
+ssh_remote_deploy/host="user@host_ip"
+ssh_remote_deploy/port="22"
+ssh_remote_deploy/extra_args_ssh=""
+ssh_remote_deploy/extra_args_scp=""
+ssh_remote_deploy/run_script="#!/usr/bin/env bash
+export DISPLAY=:0
+unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
+\"{temp_dir}/{exe_name}\" {cmd_args}"
+ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
+kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
+rm -rf \"{temp_dir}\""
+
+[preset.2]
+
+name="macOS"
+platform="macOS"
+runnable=true
+dedicated_server=false
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path=""
+encryption_include_filters=""
+encryption_exclude_filters=""
+encrypt_pck=false
+encrypt_directory=false
+
+[preset.2.options]
+
+export/distribution_type=1
+binary_format/architecture="universal"
+custom_template/debug=""
+custom_template/release=""
+debug/export_console_wrapper=1
+application/icon=""
+application/icon_interpolation=4
+application/bundle_identifier=""
+application/signature=""
+application/app_category="Games"
+application/short_version=""
+application/version=""
+application/copyright=""
+application/copyright_localized={}
+application/min_macos_version="10.12"
+application/export_angle=0
+display/high_res=true
+xcode/platform_build="14C18"
+xcode/sdk_version="13.1"
+xcode/sdk_build="22C55"
+xcode/sdk_name="macosx13.1"
+xcode/xcode_version="1420"
+xcode/xcode_build="14C18"
+codesign/codesign=1
+codesign/installer_identity=""
+codesign/apple_team_id=""
+codesign/identity=""
+codesign/entitlements/custom_file=""
+codesign/entitlements/allow_jit_code_execution=false
+codesign/entitlements/allow_unsigned_executable_memory=false
+codesign/entitlements/allow_dyld_environment_variables=false
+codesign/entitlements/disable_library_validation=false
+codesign/entitlements/audio_input=false
+codesign/entitlements/camera=false
+codesign/entitlements/location=false
+codesign/entitlements/address_book=false
+codesign/entitlements/calendars=false
+codesign/entitlements/photos_library=false
+codesign/entitlements/apple_events=false
+codesign/entitlements/debugging=false
+codesign/entitlements/app_sandbox/enabled=false
+codesign/entitlements/app_sandbox/network_server=false
+codesign/entitlements/app_sandbox/network_client=false
+codesign/entitlements/app_sandbox/device_usb=false
+codesign/entitlements/app_sandbox/device_bluetooth=false
+codesign/entitlements/app_sandbox/files_downloads=0
+codesign/entitlements/app_sandbox/files_pictures=0
+codesign/entitlements/app_sandbox/files_music=0
+codesign/entitlements/app_sandbox/files_movies=0
+codesign/entitlements/app_sandbox/files_user_selected=0
+codesign/entitlements/app_sandbox/helper_executables=[]
+codesign/custom_options=PackedStringArray()
+notarization/notarization=0
+privacy/microphone_usage_description=""
+privacy/microphone_usage_description_localized={}
+privacy/camera_usage_description=""
+privacy/camera_usage_description_localized={}
+privacy/location_usage_description=""
+privacy/location_usage_description_localized={}
+privacy/address_book_usage_description=""
+privacy/address_book_usage_description_localized={}
+privacy/calendar_usage_description=""
+privacy/calendar_usage_description_localized={}
+privacy/photos_library_usage_description=""
+privacy/photos_library_usage_description_localized={}
+privacy/desktop_folder_usage_description=""
+privacy/desktop_folder_usage_description_localized={}
+privacy/documents_folder_usage_description=""
+privacy/documents_folder_usage_description_localized={}
+privacy/downloads_folder_usage_description=""
+privacy/downloads_folder_usage_description_localized={}
+privacy/network_volumes_usage_description=""
+privacy/network_volumes_usage_description_localized={}
+privacy/removable_volumes_usage_description=""
+privacy/removable_volumes_usage_description_localized={}
+ssh_remote_deploy/enabled=false
+ssh_remote_deploy/host="user@host_ip"
+ssh_remote_deploy/port="22"
+ssh_remote_deploy/extra_args_ssh=""
+ssh_remote_deploy/extra_args_scp=""
+ssh_remote_deploy/run_script="#!/usr/bin/env bash
+unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
+open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}"
+ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
+kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")
+rm -rf \"{temp_dir}\""
+
+[preset.3]
+
+name="Android"
+platform="Android"
+runnable=true
+dedicated_server=false
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path=""
+encryption_include_filters=""
+encryption_exclude_filters=""
+encrypt_pck=false
+encrypt_directory=false
+
+[preset.3.options]
+
+custom_template/debug=""
+custom_template/release=""
+gradle_build/use_gradle_build=false
+gradle_build/export_format=0
+gradle_build/min_sdk=""
+gradle_build/target_sdk=""
+architectures/armeabi-v7a=false
+architectures/arm64-v8a=true
+architectures/x86=false
+architectures/x86_64=false
+version/code=1
+version/name=""
+package/unique_name="com.example.$genname"
+package/name=""
+package/signed=true
+package/app_category=2
+package/retain_data_on_uninstall=false
+package/exclude_from_recents=false
+package/show_in_android_tv=false
+package/show_in_app_library=true
+package/show_as_launcher_app=false
+launcher_icons/main_192x192=""
+launcher_icons/adaptive_foreground_432x432=""
+launcher_icons/adaptive_background_432x432=""
+graphics/opengl_debug=false
+xr_features/xr_mode=0
+screen/immersive_mode=true
+screen/support_small=true
+screen/support_normal=true
+screen/support_large=true
+screen/support_xlarge=true
+user_data_backup/allow=false
+command_line/extra_args=""
+apk_expansion/enable=false
+apk_expansion/SALT=""
+apk_expansion/public_key=""
+permissions/custom_permissions=PackedStringArray()
+permissions/access_checkin_properties=false
+permissions/access_coarse_location=false
+permissions/access_fine_location=false
+permissions/access_location_extra_commands=false
+permissions/access_mock_location=false
+permissions/access_network_state=false
+permissions/access_surface_flinger=false
+permissions/access_wifi_state=false
+permissions/account_manager=false
+permissions/add_voicemail=false
+permissions/authenticate_accounts=false
+permissions/battery_stats=false
+permissions/bind_accessibility_service=false
+permissions/bind_appwidget=false
+permissions/bind_device_admin=false
+permissions/bind_input_method=false
+permissions/bind_nfc_service=false
+permissions/bind_notification_listener_service=false
+permissions/bind_print_service=false
+permissions/bind_remoteviews=false
+permissions/bind_text_service=false
+permissions/bind_vpn_service=false
+permissions/bind_wallpaper=false
+permissions/bluetooth=false
+permissions/bluetooth_admin=false
+permissions/bluetooth_privileged=false
+permissions/brick=false
+permissions/broadcast_package_removed=false
+permissions/broadcast_sms=false
+permissions/broadcast_sticky=false
+permissions/broadcast_wap_push=false
+permissions/call_phone=false
+permissions/call_privileged=false
+permissions/camera=false
+permissions/capture_audio_output=false
+permissions/capture_secure_video_output=false
+permissions/capture_video_output=false
+permissions/change_component_enabled_state=false
+permissions/change_configuration=false
+permissions/change_network_state=false
+permissions/change_wifi_multicast_state=false
+permissions/change_wifi_state=false
+permissions/clear_app_cache=false
+permissions/clear_app_user_data=false
+permissions/control_location_updates=false
+permissions/delete_cache_files=false
+permissions/delete_packages=false
+permissions/device_power=false
+permissions/diagnostic=false
+permissions/disable_keyguard=false
+permissions/dump=false
+permissions/expand_status_bar=false
+permissions/factory_test=false
+permissions/flashlight=false
+permissions/force_back=false
+permissions/get_accounts=false
+permissions/get_package_size=false
+permissions/get_tasks=false
+permissions/get_top_activity_info=false
+permissions/global_search=false
+permissions/hardware_test=false
+permissions/inject_events=false
+permissions/install_location_provider=false
+permissions/install_packages=false
+permissions/install_shortcut=false
+permissions/internal_system_window=false
+permissions/internet=false
+permissions/kill_background_processes=false
+permissions/location_hardware=false
+permissions/manage_accounts=false
+permissions/manage_app_tokens=false
+permissions/manage_documents=false
+permissions/manage_external_storage=false
+permissions/master_clear=false
+permissions/media_content_control=false
+permissions/modify_audio_settings=false
+permissions/modify_phone_state=false
+permissions/mount_format_filesystems=false
+permissions/mount_unmount_filesystems=false
+permissions/nfc=false
+permissions/persistent_activity=false
+permissions/post_notifications=false
+permissions/process_outgoing_calls=false
+permissions/read_calendar=false
+permissions/read_call_log=false
+permissions/read_contacts=false
+permissions/read_external_storage=false
+permissions/read_frame_buffer=false
+permissions/read_history_bookmarks=false
+permissions/read_input_state=false
+permissions/read_logs=false
+permissions/read_phone_state=false
+permissions/read_profile=false
+permissions/read_sms=false
+permissions/read_social_stream=false
+permissions/read_sync_settings=false
+permissions/read_sync_stats=false
+permissions/read_user_dictionary=false
+permissions/reboot=false
+permissions/receive_boot_completed=false
+permissions/receive_mms=false
+permissions/receive_sms=false
+permissions/receive_wap_push=false
+permissions/record_audio=false
+permissions/reorder_tasks=false
+permissions/restart_packages=false
+permissions/send_respond_via_message=false
+permissions/send_sms=false
+permissions/set_activity_watcher=false
+permissions/set_alarm=false
+permissions/set_always_finish=false
+permissions/set_animation_scale=false
+permissions/set_debug_app=false
+permissions/set_orientation=false
+permissions/set_pointer_speed=false
+permissions/set_preferred_applications=false
+permissions/set_process_limit=false
+permissions/set_time=false
+permissions/set_time_zone=false
+permissions/set_wallpaper=false
+permissions/set_wallpaper_hints=false
+permissions/signal_persistent_processes=false
+permissions/status_bar=false
+permissions/subscribed_feeds_read=false
+permissions/subscribed_feeds_write=false
+permissions/system_alert_window=false
+permissions/transmit_ir=false
+permissions/uninstall_shortcut=false
+permissions/update_device_stats=false
+permissions/use_credentials=false
+permissions/use_sip=false
+permissions/vibrate=false
+permissions/wake_lock=false
+permissions/write_apn_settings=false
+permissions/write_calendar=false
+permissions/write_call_log=false
+permissions/write_contacts=false
+permissions/write_external_storage=false
+permissions/write_gservices=false
+permissions/write_history_bookmarks=false
+permissions/write_profile=false
+permissions/write_secure_settings=false
+permissions/write_settings=false
+permissions/write_sms=false
+permissions/write_social_stream=false
+permissions/write_sync_settings=false
+permissions/write_user_dictionary=false
diff --git a/demo/icon.svg b/demo/icon.svg
new file mode 100644
index 0000000..3fe4f4a
--- /dev/null
+++ b/demo/icon.svg
@@ -0,0 +1 @@
+
diff --git a/demo/icon.svg.import b/demo/icon.svg.import
new file mode 100644
index 0000000..383529b
--- /dev/null
+++ b/demo/icon.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cuend5rtkhbnp"
+path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.svg"
+dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/demo/main.tscn b/demo/main.tscn
new file mode 100644
index 0000000..04cbbac
--- /dev/null
+++ b/demo/main.tscn
@@ -0,0 +1,10 @@
+[gd_scene load_steps=2 format=3 uid="uid://uiwigxsdnci1"]
+
+[ext_resource type="Texture2D" uid="uid://cuend5rtkhbnp" path="res://icon.svg" id="1_q81dj"]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="GDExample" type="GDExample" parent="."]
+position = Vector2(5.20978, 6.34048)
+texture = ExtResource("1_q81dj")
+centered = false
diff --git a/demo/project.godot b/demo/project.godot
new file mode 100644
index 0000000..9d0b642
--- /dev/null
+++ b/demo/project.godot
@@ -0,0 +1,16 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="demo"
+run/main_scene="res://main.tscn"
+config/features=PackedStringArray("4.2", "Forward Plus")
+config/icon="res://icon.svg"
diff --git a/src/gdexample.cpp b/src/gdexample.cpp
new file mode 100644
index 0000000..2f6042e
--- /dev/null
+++ b/src/gdexample.cpp
@@ -0,0 +1,28 @@
+
+#include "gdexample.h"
+#include
+
+using namespace godot;
+
+void GDExample::_bind_methods() {
+ // ClassDB::bind_method(D_METHOD("_process", "delta"), &GDExample::_process);
+}
+
+GDExample::GDExample()
+{
+ time_passed = 0.0;
+
+}
+
+GDExample::~GDExample() {}
+
+void GDExample::_process(float delta)
+{
+ time_passed += delta;
+
+ auto new_position = Vector2(
+ 10.0 + (10.0 * sin(time_passed * 2.0)),
+ 10.0 + (10.0 * cos(time_passed * 1.5)));
+
+ set_position(new_position);
+}
\ No newline at end of file
diff --git a/src/gdexample.h b/src/gdexample.h
new file mode 100644
index 0000000..63d3c50
--- /dev/null
+++ b/src/gdexample.h
@@ -0,0 +1,24 @@
+#ifndef GDEXAMPLE_H
+#define GDEXAMPLE_H
+
+#include
+
+namespace godot
+{
+ class GDExample : public Sprite2D
+ {
+ GDCLASS(GDExample, Sprite2D)
+ private:
+ double time_passed;
+
+ protected:
+ static void _bind_methods();
+
+ public:
+ GDExample();
+ ~GDExample();
+
+ void _process(float delta);
+ };
+}
+#endif
\ No newline at end of file
diff --git a/src/register_types.cpp b/src/register_types.cpp
new file mode 100644
index 0000000..d36ecdd
--- /dev/null
+++ b/src/register_types.cpp
@@ -0,0 +1,44 @@
+#include "register_types.h"
+
+#include "gdexample.h"
+
+#include
+#include
+#include
+
+using namespace godot;
+
+void initialize_example_module(ModuleInitializationLevel p_level)
+{
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE)
+ {
+ return;
+ }
+
+ ClassDB::register_class();
+}
+
+void uninitialize_example_module(ModuleInitializationLevel p_level)
+{
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE)
+ {
+ return;
+ }
+}
+
+extern "C"
+{
+ GDExtensionBool GDE_EXPORT library_init(
+ GDExtensionInterfaceGetProcAddress p_get_proc,
+ const GDExtensionClassLibraryPtr p_library,
+ GDExtensionInitialization *r_initialization)
+ {
+ godot::GDExtensionBinding::InitObject init_obj(p_get_proc, p_library, r_initialization);
+
+ init_obj.register_initializer(initialize_example_module);
+ init_obj.register_terminator(uninitialize_example_module);
+ init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
+
+ return init_obj.init();
+ }
+}
\ No newline at end of file
diff --git a/src/register_types.h b/src/register_types.h
new file mode 100644
index 0000000..938f7a1
--- /dev/null
+++ b/src/register_types.h
@@ -0,0 +1,11 @@
+#ifndef GDEXAMPLE_REGISTER_TYPES_H
+#define GDEXAMPLE_REGISTER_TYPES_H
+
+#include
+
+using namespace godot;
+
+void initialize_example_module(ModuleInitializationLevel p_level);
+void uninitialize_example_module(ModuleInitializationLevel p_level);
+
+#endif
\ No newline at end of file
diff --git a/templates/class_tpl.lua b/templates/class_tpl.lua
new file mode 100644
index 0000000..aae42f7
--- /dev/null
+++ b/templates/class_tpl.lua
@@ -0,0 +1,103 @@
+--[[
+ #ifndef $(HEADER_GUARD)
+ #define $(HEADER_GUARD)
+
+ #include
+
+ namespace $(NAMESPACE)
+ {
+ class $(CLASS_NAME) : public godot::$(BASE_CLASS)
+ {
+ GDCLASS($(CLASS_NAME), godot::$(BASE_CLASS)
+
+ protected:
+ static void _bind_methods();
+
+ public:
+ $(CLASS_NAME)();
+ ~$(CLASS_NAME)();
+
+ void _process(float delta);
+ };
+ }
+ #endif
+
+]]
+
+function render_header(header_guard, namespace, class_name, base_class)
+ local template = {
+ string.format("#ifndef %s", header_guard),
+ string.format("#define %s", header_guard),
+ string.format("#include ", string.lower(base_class)),
+ string.format("namespace %s", namespace),
+ "{",
+ string.format(" class %s : public godot::%s", class_name, base_class),
+ " {",
+ string.format(" GDCLASS(%s, godot::%s)", class_name, base_class),
+ " protected:",
+ string.format(" static void _bind_methods();"),
+ string.format(" public:"),
+ string.format(" %s();", class_name),
+ string.format(" ~%s();", class_name),
+ string.format(" void _process(float delta);"),
+ " };",
+ "}",
+ "#endif",
+ }
+
+ return table.concat(template, "\n")
+end
+
+--[[
+
+#include "{% echo(" " .. string.lower(ClassName)) %}.h"
+
+using namespace {*Namespace*};
+
+void {*ClassName*}::_bind_methods() {
+ // bind your own methods here, like
+ // ClassDB::bind_method(D_METHOD("my_foo", "delta"), &{ClassName}::my_foo);
+}
+
+{*ClassName*}::{*ClassName*}()
+{
+ // initialize here
+}
+
+{*ClassName*}::~{*ClassName*}() {}
+
+void {*ClassName*}::_process(float delta)
+{
+ // do update here
+}
+]]
+
+function render_impl(namespace, classname)
+ local template = {
+ string.format("#include \"%s.h\"", string.lower(classname)),
+ string.format("using namespace %s;", namespace),
+ "",
+ string.format("void %s::_bind_methods()", classname),
+ "{",
+ " // bind your own methods here, like",
+ string.format(" // ClassDB::bind_method(D_METHOD(\"my_foo\", \"delta\"), &%s::my_foo);", classname),
+ "}",
+ "",
+ string.format("%s::%s()", classname, classname),
+ "{",
+ " // initialize here",
+ "}",
+ "",
+ string.format("%s::~%s()", classname, classname),
+ "{",
+ " // do clean up here",
+ "}",
+ "",
+ string.format("void %s::_process(float delta)", classname),
+ "{",
+ " // do update here",
+ "}"
+ }
+
+ return table.concat(template, "\n")
+end
\ No newline at end of file
diff --git a/xmake.lua b/xmake.lua
new file mode 100644
index 0000000..fbec89d
--- /dev/null
+++ b/xmake.lua
@@ -0,0 +1,21 @@
+-- TODO:
+-- 1. support other platforms
+-- 2. switch optimization level
+-- 3. refine the run command, as it currently run the project by default, maybe start a demo scene or a specified scene?
+
+------- basic custom config part -------
+
+-- project name
+PROJECT_NAME = "gdexample"
+
+-- project version
+VERSION = "0.0.1"
+
+-- godot project folder, this will be used as export name, so be careful to make sure it is a valid name
+GODOT_PROJECT_FOLDER = "demo"
+
+-- publish folder, the exported files will be put here
+PUBLISH_FOLDER = "publish"
+
+
+includes("xmake/godot.lua")
\ No newline at end of file
diff --git a/xmake/editor.lua b/xmake/editor.lua
new file mode 100644
index 0000000..1e505a9
--- /dev/null
+++ b/xmake/editor.lua
@@ -0,0 +1,15 @@
+target("Editor")
+ set_default(false)
+
+ -- Disable building
+ on_build((function() end))
+
+ on_run(
+ (function(godot_project_folder)
+ return function(target)
+ local project_file = path.join(godot_project_folder, "project.godot")
+ os.execv("echo", {"godot", project_file})
+ os.exec("godot " .. project_file)
+ end
+ end)(GODOT_PROJECT_FOLDER)
+ )
\ No newline at end of file
diff --git a/xmake/godot.lua b/xmake/godot.lua
new file mode 100644
index 0000000..f520ac5
--- /dev/null
+++ b/xmake/godot.lua
@@ -0,0 +1,26 @@
+------- project settings -------
+
+-- project name
+set_project(PROJECT_NAME)
+
+-- project version
+set_version(VERSION)
+
+-- min version of xmake we need to run
+-- NOTE: this is the version i used to develop this template, may not 100% correct
+set_xmakever("2.9.0")
+
+add_rules("mode.debug", "mode.release")
+
+-- c++17 is required for godot 4.x, we use c++20 here
+set_languages("c++20")
+
+-- use latest 4.x version by default
+add_requires("godotcpp4")
+
+
+includes("tasks.lua")
+
+includes("target.lua")
+
+includes("editor.lua")
\ No newline at end of file
diff --git a/xmake/target.lua b/xmake/target.lua
new file mode 100644
index 0000000..5d245eb
--- /dev/null
+++ b/xmake/target.lua
@@ -0,0 +1,65 @@
+-- more on https://xmake.io/#/manual/project_target
+target(PROJECT_NAME)
+ set_kind("shared")
+ set_default(true)
+
+ add_packages("godotcpp4")
+
+ -- more on https://xmake.io/#/manual/project_target?id=targetadd_files
+ add_files("../src/**.cpp")
+
+ -- change the output name
+ set_basename(PROJECT_NAME .. ".$(os)_$(mode)_$(arch)")
+
+ -- libraries will saved in os level folder
+ set_targetdir("../" .. GODOT_PROJECT_FOLDER .. "/lib")
+
+ -- where to save .obj files
+ -- we use a seprate folder, so that it will not populate the targer folder
+ set_objectdir("../build/.objs")
+
+ -- where .d files are saved
+ set_dependir("../build/.deps")
+
+ -- set_optimize("smallest")
+
+ -- handlers
+
+ -- before_run(function (target) end)
+ -- after_run(function (target) end)
+ -- before_build(function (target) end)
+ -- after_build(function (target) end)
+ -- before_clean(function (target) end)
+ -- after_clean(function (target) end)
+
+ on_run(
+ (function(godot_project_folder)
+ return function(target)
+ os.execv("echo", {"godot --path", godot_project_folder})
+ os.exec("godot --path " .. godot_project_folder)
+ end
+ end)(GODOT_PROJECT_FOLDER)
+ )
+
+ on_package(function(target)
+ import("core.base.task")
+
+ target_platform = "Unknown"
+
+ if is_plat("windows") then
+ target_platform = "Windows Desktop"
+ elseif is_plat("macosx") then
+ target_platform = "macOS"
+ elseif is_plat("linux") then
+ target_platform = "Linux/X11"
+ elseif is_plat("android") then
+ target_platform = "Android"
+ end
+
+ task.run("export", {}, target_platform)
+ end)
+
+ after_clean(function (target)
+ import("core.base.task")
+ task.run("clean-publish")
+ end)
\ No newline at end of file
diff --git a/xmake/tasks.lua b/xmake/tasks.lua
new file mode 100644
index 0000000..b937bd5
--- /dev/null
+++ b/xmake/tasks.lua
@@ -0,0 +1,204 @@
+-- NOTE:
+-- xmake cannot accept the global variables in on_xxx functions, so we use a wrapper function to bind it
+
+-- export specified godot project, with the export execution name
+-- args:
+-- target_platform: the target platform, like "Windows Desktop"
+-- name: the export execute name, it will be endswith ".exe" on windows
+task("export")
+ on_run((function(godot_project_folder, publish_folder)
+ return function(target_platform)
+ local name = godot_project_folder
+
+ -- different platform may have different execute name
+ -- xmake supported platforms:
+ -- windows
+ -- cross
+ -- linux
+ -- macosx
+ -- android
+ -- iphoneos
+ -- watchos
+ if is_plat("windows") then
+ name = name .. ".exe"
+ end
+
+ local export_mode = "export-debug"
+
+ if is_mode("release") then
+ export_mode = "export-release"
+ end
+
+ if not os.isdir(publish_folder) then
+ os.mkdir(publish_folder)
+ end
+
+ local godot_project_file = path.join(godot_project_folder, "project.godot")
+
+ local export_path = path.absolute(path.join(publish_folder, name))
+
+ os.execv("echo", {"godot", godot_project_file, export_mode, target_platform, export_path})
+ os.exec("godot %s --headless --%s %s %s", godot_project_file, export_mode, "\"" .. target_platform .. "\"", export_path)
+ end
+
+ end)(GODOT_PROJECT_FOLDER, PUBLISH_FOLDER))
+task_end()
+
+
+
+
+
+-- clean the publish folder and build folder
+task("clean-publish")
+ on_run((function(godot_project_folder, publish_folder)
+ return function ()
+ -- remove publish folder
+ if os.isdir(publish_folder) then
+ os.tryrm(publish_folder)
+ end
+
+ -- remove build target folder
+ local bin_dir = path.join(godot_project_folder, "bin")
+ if os.isdir(bin_dir) then
+ os.tryrm(path.join(bin_dir, "$(os)"))
+ end
+ end
+ end)(GODOT_PROJECT_FOLDER, PUBLISH_FOLDER))
+task_end()
+
+
+-- tasks that exposed to cli
+-- NOTE: for complex tasks, we can use a seprate file to define it
+
+-- generate a class that inherit from godot class
+-- args:
+-- name: the new class name
+-- basename: the base class name to inherit (must under godot_cpp/classes)
+-- dir: the directory to save the class (must under src)
+-- namespace: the namespace of the new class
+
+task("ext-class")
+ on_run(function ()
+ -- more on: https://xmake.io/#/manual/plugin_task
+ -- we need this module to load options from menu
+ import "core.base.option"
+
+ local namespace = option.get("namespace")
+ local name = option.get("name")
+ local base = option.get("base")
+ local dir = option.get("dir")
+
+ -- we calculate these here, in case there is any special case to handle
+ local header_guard = string.upper(name) .. "_H"
+
+ import("class_tpl", {rootdir="templates", alias="class_render"})
+
+ -- header and impl text
+ local header_text = class_render.render_header(header_guard, namespace, name, base)
+ local impl_text = class_render.render_impl(namespace, name)
+
+ -- save
+ local output_dir = "src"
+
+ if dir ~= nil then
+ output_dir = path.join("src", dir)
+ end
+
+ if not os.isdir(output_dir) then
+ os.mkdir(output_dir)
+ end
+
+ local header_file = path.join(output_dir, string.lower(name) .. ".h")
+ local impl_file = path.join(output_dir, string.lower(name) .. ".cpp")
+
+ io.writefile(header_file, header_text)
+ io.writefile(impl_file, impl_text)
+
+ end)
+
+ -- options
+ set_menu {
+ usage = "xmake ext-class [options]",
+
+ description = "Generate godot class that inherits from a base class under godot_cpp/classes",
+
+ options = {
+
+ -- kv options
+ -- (short, long), (kv, default_value), description, [values])
+ {"s", "namespace", "kv", "godot", "Set the namespace of the new class"},
+ {"d", "dir", "kv", nil, "Set the directory to save the class"},
+
+ {},
+
+ -- single value options
+ {"n", "name", "v", nil, "Set the new class name"},
+ {"b", "base", "v", nil, "Set the base class name to inherit"},
+ }
+ }
+task_end()
+
+
+
+
+
+task("gengdextension")
+ on_run((function(godot_project_folder, project_name)
+ return function ()
+
+ local bin_dir = path.join(godot_project_folder, "bin")
+ if not os.isdir(bin_dir) then
+ os.mkdir(bin_dir)
+ end
+
+ local godot_gdextension_file = path.join(bin_dir, project_name .. ".gdextension")
+
+ local fileContent =
+[[
+[icons]
+ProjectName = "res://icon.svg"
+
+[configuration]
+
+entry_symbol = "library_init"
+compatibility_minimum = "4.2"
+
+[libraries]
+
+macos.debug = "res://lib/libProjectName.macos_framework"
+macos.release = "res://lib/libProjectName.macos_framework"
+
+window.debug.x86_32 = "res://lib/libProjectName.windows_debug_x86.dll"
+window.release.x86_32 = "res://lib/libProjectName.windows_release_x86.dll"
+window.debug.x86_64 = "res://lib/libProjectName.windows_debug_x64.dll"
+window.release.x86_64 = "res://lib/libProjectName.windows_release_x64.dll"
+
+linux.debug.x86_64 = "res://lib/libProjectName.linux_debug_x86_64.so"
+linux.release.x86_64 = "res://lib/libProjectName.linux_release_x86_64.so"
+linux.debug.arm64 = "res://lib/libProjectName.linux_debug_arm64.so"
+linux.release.arm64 = "res://lib/libProjectName.linux_release_arm64.so"
+linux.debug.rv64 = "res://lib/libProjectName.linux_debug_rv64.so"
+linux.release.rv64 = "res://lib/libProjectName.linux_release_rv64.so"
+
+android.debug.x86_64 = "res://lib/libProjectName.android_debug_x86_64.so"
+android.release.x86_64 = "res://lib/libProjectName.android_release_x86_64.so"
+android.debug.arm64 = "res://lib/libProjectName.android_debug_arm64.so"
+android.release.arm64 = "res://lib/libProjectName.android_release_arm64.so"
+
+]]
+
+ -- needs testing with macos
+
+ fileContent = string.gsub(fileContent, "ProjectName", project_name)
+
+ io.writefile(godot_gdextension_file, fileContent)
+ end
+ end)(GODOT_PROJECT_FOLDER, PROJECT_NAME))
+
+ -- options
+ set_menu {
+ usage = "xmake gengdextension",
+
+ description = "Generate gdextension file",
+ }
+task_end()