Implement working example

Implement a working example using the GDExtension C API.
This commit is contained in:
Aidan Mullen 2024-05-04 10:05:16 -04:00
parent 2c4cdb41a1
commit f8025b805a
4 changed files with 25 additions and 33 deletions

10
.gitignore vendored
View file

@ -16,10 +16,6 @@
!README !README
!TODO !TODO
# /bin
!/bin/
/bin/*
!/bin/main.gdextension !/bin/main.gdextension
# /docs # /docs
@ -35,6 +31,12 @@
!/engine/project.godot !/engine/project.godot
!/engine/icon.svg !/engine/icon.svg
# /engine/bin
!/engine/bin
/engine/bin/*
!/engine/bin/librtr.gdextension
# /src # /src
!/src/ !/src/
/src/* /src/*

View file

@ -1,8 +0,0 @@
[configuration]
entry_symbol = "rtr_extension_init"
compatibility_minimum = "4.2"
[libraries]
windows.x86_64 = "../src/.libs/librtr.dll"
macos = "../src/.libs/librtr.dylib"
linux.debug.x86_64 = "res://../src/.libs/librtr.so"

View file

@ -0,0 +1,8 @@
[configuration]
entry_symbol = "librtr_extension_init"
compatibility_minimum = "4.2"
[libraries]
windows.x86_64 = "res://../src/.libs/librtr.dll"
macos = "res://../src/.libs/librtr.dylib"
linux.debug.x86_64 = "res://../src/.libs/librtr.so"

View file

@ -19,6 +19,9 @@ int main()
} }
*/ */
/* Boilerplate provided by examples. */
/* Some lines are over 80 characters. */
typedef struct { typedef struct {
uint8_t godot_data_dont_touch_this[sizeof(void *)]; uint8_t godot_data_dont_touch_this[sizeof(void *)];
} String; } String;
@ -31,55 +34,46 @@ typedef struct {
uint8_t godot_data_dont_touch_this[24]; uint8_t godot_data_dont_touch_this[24];
} Variant; } Variant;
// GDExtension interface function pointers
static GDExtensionInterfaceStringNewWithUtf8Chars string_new_with_utf8_chars; static GDExtensionInterfaceStringNewWithUtf8Chars string_new_with_utf8_chars;
static GDExtensionInterfaceVariantGetPtrConstructor variant_get_ptr_constructor; static GDExtensionInterfaceVariantGetPtrConstructor variant_get_ptr_constructor;
static GDExtensionInterfaceVariantGetPtrDestructor variant_get_ptr_destructor; static GDExtensionInterfaceVariantGetPtrDestructor variant_get_ptr_destructor;
static GDExtensionInterfaceGetVariantFromTypeConstructor get_variant_from_type_constructor; static GDExtensionInterfaceGetVariantFromTypeConstructor get_variant_from_type_constructor;
static GDExtensionInterfaceVariantGetPtrUtilityFunction variant_get_ptr_utility_function; static GDExtensionInterfaceVariantGetPtrUtilityFunction variant_get_ptr_utility_function;
static GDExtensionInterfaceVariantDestroy variant_destroy; static GDExtensionInterfaceVariantDestroy variant_destroy;
// Godot API function pointers
/* GDExtension API Pointers */
static GDExtensionPtrConstructor construct_StringName_from_String; static GDExtensionPtrConstructor construct_StringName_from_String;
static GDExtensionVariantFromTypeConstructorFunc construct_Variant_from_String; static GDExtensionVariantFromTypeConstructorFunc construct_Variant_from_String;
static GDExtensionPtrDestructor destroy_String; static GDExtensionPtrDestructor destroy_String;
static GDExtensionPtrDestructor destroy_StringName; static GDExtensionPtrDestructor destroy_StringName;
// here is our global "print" StringName
static StringName print_StringName; static StringName print_StringName;
// and here is our global "print" function
static GDExtensionPtrUtilityFunction print_function; static GDExtensionPtrUtilityFunction print_function;
StringName construct_StringName_from_cstring(const char *text) { StringName construct_StringName_from_cstring(const char *text) {
// 1. Construct a String from the C string
String string; String string;
string_new_with_utf8_chars(&string, text); string_new_with_utf8_chars(&string, text);
// 2. Construct a StringName from the String
StringName string_name; StringName string_name;
GDExtensionConstTypePtr constructor_arguments[1] = { &string }; GDExtensionConstTypePtr constructor_arguments[1] = { &string };
construct_StringName_from_String(&string_name, constructor_arguments); construct_StringName_from_String(&string_name, constructor_arguments);
// 3. Destroy the String, since it's not needed anymore
destroy_String(&string); destroy_String(&string);
return string_name; return string_name;
} }
void print(const char *text) { void print(const char *text) {
// 1. Construct a String from the C string
String string; String string;
string_new_with_utf8_chars(&string, text); string_new_with_utf8_chars(&string, text);
// 2. Construct a Variant from the String
Variant arg1; Variant arg1;
construct_Variant_from_String(&arg1, &string); construct_Variant_from_String(&arg1, &string);
// 3. Call the utility function
// Since it's a void function, use "NULL" for the return pointer
GDExtensionConstVariantPtr args[1] = { &arg1 }; GDExtensionConstVariantPtr args[1] = { &arg1 };
print_function(NULL, args, 1); print_function(NULL, args, 1);
// 4. Clean up resources that are no longer needed
variant_destroy(&arg1); variant_destroy(&arg1);
destroy_String(&string); destroy_String(&string);
} }
@ -89,19 +83,15 @@ void initialize(void *userdata, GDExtensionInitializationLevel p_level) {
return; return;
} }
// StringName constructor at index 2 is the one that receives String
// You can find this information in `extension_api.json` file
construct_StringName_from_String = variant_get_ptr_constructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME, 2); construct_StringName_from_String = variant_get_ptr_constructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME, 2);
construct_Variant_from_String = get_variant_from_type_constructor(GDEXTENSION_VARIANT_TYPE_STRING); construct_Variant_from_String = get_variant_from_type_constructor(GDEXTENSION_VARIANT_TYPE_STRING);
destroy_String = variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING); destroy_String = variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING);
destroy_StringName = variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME); destroy_StringName = variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME);
// Initialize "print" StringName
print_StringName = construct_StringName_from_cstring("print"); print_StringName = construct_StringName_from_cstring("print");
// then fetch the "print" function pointer
print_function = variant_get_ptr_utility_function(&print_StringName, 2648703342); print_function = variant_get_ptr_utility_function(&print_StringName, 2648703342);
print("Hello GDExtension from C!"); print("Starting...");
} }
void deinitialize(void *userdata, GDExtensionInitializationLevel p_level) { void deinitialize(void *userdata, GDExtensionInitializationLevel p_level) {
@ -109,20 +99,20 @@ void deinitialize(void *userdata, GDExtensionInitializationLevel p_level) {
return; return;
} }
print("Goodbye GDExtension from C!"); print("Exited.");
// Destroy "print" StringName
destroy_StringName(&print_StringName); destroy_StringName(&print_StringName);
} }
GDExtensionBool hello_extension_entry( /* librtr object; called by Godot when it reads the librtr.gdextension file that
* provides a configuration using this name. */
GDExtensionBool librtr_extension_init(
GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionInterfaceGetProcAddress p_get_proc_address,
GDExtensionClassLibraryPtr p_library, GDExtensionClassLibraryPtr p_library,
GDExtensionInitialization *r_initialization GDExtensionInitialization *r_initialization
) { ) {
r_initialization->initialize = &initialize; r_initialization->initialize = &initialize;
r_initialization->deinitialize = &deinitialize; r_initialization->deinitialize = &deinitialize;
// save the GDExtension API function pointers globally
string_new_with_utf8_chars = (GDExtensionInterfaceStringNewWithUtf8Chars) p_get_proc_address("string_new_with_utf8_chars"); string_new_with_utf8_chars = (GDExtensionInterfaceStringNewWithUtf8Chars) p_get_proc_address("string_new_with_utf8_chars");
variant_get_ptr_constructor = (GDExtensionInterfaceVariantGetPtrConstructor) p_get_proc_address("variant_get_ptr_constructor"); variant_get_ptr_constructor = (GDExtensionInterfaceVariantGetPtrConstructor) p_get_proc_address("variant_get_ptr_constructor");
variant_get_ptr_destructor = (GDExtensionInterfaceVariantGetPtrDestructor) p_get_proc_address("variant_get_ptr_destructor"); variant_get_ptr_destructor = (GDExtensionInterfaceVariantGetPtrDestructor) p_get_proc_address("variant_get_ptr_destructor");