|
@@ -7,22 +7,25 @@ Introduction
|
|
|
------------
|
|
|
|
|
|
This tutorial will introduce you to the bare minimum required to create GDNative
|
|
|
-modules. This should be your starting point into the world of GDNative,
|
|
|
-understanding the contents of this tutorial will help you in understanding all
|
|
|
+modules. This should be your starting point into the world of GDNative.
|
|
|
+Understanding the contents of this tutorial will help you in understanding all
|
|
|
that is to come after this.
|
|
|
|
|
|
-Before we begin, you can download the source code to the example object we'll be
|
|
|
-describing here by following this link:
|
|
|
-https://github.com/GodotNativeTools/GDNative-demos/tree/master/c/SimpleDemo
|
|
|
+Before we begin, you can download the source code to the example object we
|
|
|
+describe below in the `GDNative-demos repository
|
|
|
+<https://github.com/GodotNativeTools/GDNative-demos/tree/master/c/SimpleDemo>`_.
|
|
|
|
|
|
This example project also contains a SConstruct file that makes compiling a
|
|
|
-little easier but in this tutorial we'll be doing things by hand.
|
|
|
+little easier, but in this tutorial we'll be doing things by hand to
|
|
|
+understand the process.
|
|
|
|
|
|
:ref:`GDNative <class_GDNative>` can be used to create several types of
|
|
|
-additions to Godot, from PluginScript to ARVR interfaces. In this tutorial we
|
|
|
-are going to look at creating a :ref:`NativeScript <class_NativeScript>` module.
|
|
|
-NativeScript allows you to write logic in C or C++ in similar fashion as you
|
|
|
-would write a GDScript file. We'll be creating the C equivalent of this
|
|
|
+additions to Godot, using interfaces such as
|
|
|
+:ref:`PluginScript <class_PluginScript>` or
|
|
|
+:ref:`ARVRInterfaceGDNative <class_ARVRInterfaceGDNative>`. In this tutorial we
|
|
|
+are going to look at creating a :ref:`NativeScript <class_NativeScript>`
|
|
|
+module. NativeScript allows you to write logic in C or C++ in a similar fashion
|
|
|
+as you would write a GDScript file. We'll be creating the C equivalent of this
|
|
|
GDScript:
|
|
|
|
|
|
::
|
|
@@ -37,24 +40,24 @@ GDScript:
|
|
|
func get_data():
|
|
|
return data
|
|
|
|
|
|
-We'll be writing separate tutorials on the other types of GDNative modules and
|
|
|
-explain what each of them is for as we go through them.
|
|
|
+Future tutorials will focus on the other types of GDNative modules and explain
|
|
|
+when and how to use each of them.
|
|
|
|
|
|
Prerequisites
|
|
|
-------------
|
|
|
|
|
|
-Before we start you'll need a few things.
|
|
|
+Before we start you'll need a few things:
|
|
|
|
|
|
-1) A Godot 3.0 executable
|
|
|
-2) A C compiler
|
|
|
-3) A copy of this repository: https://github.com/GodotNativeTools/godot_headers
|
|
|
+1) A Godot executable for your target version.
|
|
|
+2) A C compiler. On Linux, install ``gcc`` or ``clang`` from your package
|
|
|
+ manager. On macOS, you can install Xcode from the Mac App Store. On Windows,
|
|
|
+ you can use Visual Studio 2015 or later, or MinGW-w64.
|
|
|
+3) A Git clone of the `godot_headers
|
|
|
+ repository <https://github.com/GodotNativeTools/godot_headers>`_: these are
|
|
|
+ the C headers for Godot's public API exposed to GDNative.
|
|
|
|
|
|
-The first two pretty much speak for themselves. On Linux, you'll likely have a C
|
|
|
-compiler, on macOS, it's easiest to install Xcode from the Mac App Store and, on
|
|
|
-Windows, we've tested this with both MSVC 2015 and 2017.
|
|
|
-
|
|
|
-For number 3, we suggest that you create a folder somewhere that you use to
|
|
|
-store your code, open up a terminal and CD into that folder. Then execute:
|
|
|
+For the latter, we suggest that you create a dedicated folder for this GDNative
|
|
|
+example project, open a terminal in that folder and execute:
|
|
|
|
|
|
.. code-block:: none
|
|
|
|
|
@@ -62,24 +65,38 @@ store your code, open up a terminal and CD into that folder. Then execute:
|
|
|
|
|
|
This will download the required files into that folder.
|
|
|
|
|
|
+.. tip::
|
|
|
+
|
|
|
+ If you plan to use Git for your GDNative project, you can also add
|
|
|
+ ``godot_headers`` as a Git submodule.
|
|
|
+
|
|
|
.. note::
|
|
|
|
|
|
- On this repository you will now find different branches. As Godot evolves, so
|
|
|
- does GDNative. With the exception of one breaking change in ARVR between 3.0
|
|
|
- and 3.1, GDNative modules build for older versions of Godot will work with
|
|
|
- newer versions of Godot but not the other way around.
|
|
|
+ The ``godot_headers`` repository has different branches. As Godot evolves,
|
|
|
+ so does GDNative. While we try to preserve compatibility between version,
|
|
|
+ you should always build your GDNative module against headers matching the
|
|
|
+ Godot stable branch (e.g. ``3.1``) and ideally actual release (e.g.
|
|
|
+ ``3.1.1-stable``) that you use.
|
|
|
+ GDNative modules built against older versions of the Godot headers *may*
|
|
|
+ work with newer versions of the engine, but not the other way around.
|
|
|
|
|
|
-The master branch of the ``godot_headers`` repository is kept in line with the
|
|
|
-master branch of Godot and thus contains the GDNative class and structure
|
|
|
-definitions that will work with the latest Godot master.
|
|
|
+The ``master`` branch of the ``godot_headers`` repository is kept in line with
|
|
|
+the ``master`` branch of Godot and thus contains the GDNative class and
|
|
|
+structure definitions that will work with the latest development builds.
|
|
|
|
|
|
-The 3.0 branch of the ``godot_headers`` repository contains the GDNative class
|
|
|
-and structure definitions that will work with Godot 3.0. You can clone this
|
|
|
-branch by executing:
|
|
|
+If you want to write a GDNative module for a stable version of Godot, look at
|
|
|
+the available Git tags (with ``git tags``) for the one matching your engine
|
|
|
+version. In the ``godot_headers`` repository, such tags are prefixed with
|
|
|
+``godot-``, so you can e.g. checkout the ``godot-3.1.1-stable`` tag for use with
|
|
|
+Godot 3.1.1. In your cloned repository, you can do:
|
|
|
|
|
|
.. code-block:: none
|
|
|
|
|
|
- git clone https://github.com/GodotNativeTools/godot_headers -b 3.0
|
|
|
+ git checkout godot-3.1.1-stable
|
|
|
+
|
|
|
+If a tag matching your stable release is missing for any reason, you can fall
|
|
|
+back to the matching stable branch (e.g. ``3.1``), which you would also check
|
|
|
+out with ``git checkout 3.1``.
|
|
|
|
|
|
If you are building Godot from source with your own changes that impact
|
|
|
GDNative, you can find the updated class and structure definition in
|
|
@@ -88,8 +105,8 @@ GDNative, you can find the updated class and structure definition in
|
|
|
Our C source
|
|
|
------------
|
|
|
|
|
|
-Let's start by writing our main code. Ideally, we want to end up with a file
|
|
|
-structure that looks something like this:
|
|
|
+Let's start by writing our main code. Eventually, we want to end up with a file
|
|
|
+structure that looks along those lines:
|
|
|
|
|
|
.. code-block:: none
|
|
|
|
|
@@ -107,65 +124,66 @@ structure that looks something like this:
|
|
|
main.tscn
|
|
|
project.godot
|
|
|
|
|
|
-Open up Godot and create a new project called simple. This will create the
|
|
|
-``simple`` folder and ``project.godot`` file. Then manually create a ``bin`` and
|
|
|
-``src`` subfolder in this folder.
|
|
|
+Open up Godot and create a new project called "simple" alongside your
|
|
|
+``godot_headers`` Git clone. This will create the ``simple`` folder and
|
|
|
+``project.godot`` file. Then manually create ``bin`` and ``src`` subfolders in
|
|
|
+this folder.
|
|
|
|
|
|
We're going to start by having a look at what our ``simple.c`` file contains.
|
|
|
Now, for our example here we're making a single C source file without a header
|
|
|
to keep things simple. Once you start writing bigger projects it is advisable
|
|
|
-you break your project up into multiple files. That however falls outside of the
|
|
|
+to break your project up into multiple files. That however falls outside of the
|
|
|
scope of this tutorial.
|
|
|
|
|
|
We'll be looking at the source code bit by bit so all the parts below should all
|
|
|
-be put together into one big file. I'll explain each section as we add it.
|
|
|
-
|
|
|
-The below code includes our header files that we need and then defines two
|
|
|
-pointers to two different structs. GDNative supports a large collection for
|
|
|
-functions for calling back into the main Godot executable. In order for your
|
|
|
-module to have access to these functions, GDNative provides your application
|
|
|
-with a struct containing pointers to all these functions.
|
|
|
-
|
|
|
-To keep this implementation modular and easily extendable, the core functions
|
|
|
-are available directly through the "core" API struct, but additional functions
|
|
|
-have their own "GDNative structs" that are accessible through extensions.
|
|
|
-
|
|
|
-In our example, we access one of these extension to gain access to the functions
|
|
|
-specifically needed for NativeScript.
|
|
|
+be put together into one big file. Each section will be explained as we add it.
|
|
|
|
|
|
.. code-block:: C
|
|
|
|
|
|
#include <gdnative_api_struct.gen.h>
|
|
|
- #include <stdio.h>
|
|
|
- #include <stdlib.h>
|
|
|
+
|
|
|
#include <string.h>
|
|
|
|
|
|
const godot_gdnative_core_api_struct *api = NULL;
|
|
|
const godot_gdnative_ext_nativescript_api_struct *nativescript_api = NULL;
|
|
|
|
|
|
+The above code includes the GDNative API struct header and a standard header
|
|
|
+that we will use further down for string operations.
|
|
|
+It then defines two pointers to two different structs. GDNative supports a large
|
|
|
+collection of functions for calling back into the main Godot executable. In
|
|
|
+order for your module to have access to these functions, GDNative provides your
|
|
|
+application with a struct containing pointers to all these functions.
|
|
|
+
|
|
|
+To keep this implementation modular and easily extendable, the core functions
|
|
|
+are available directly through the "core" API struct, but additional functions
|
|
|
+have their own "GDNative structs" that are accessible through extensions.
|
|
|
+
|
|
|
+In our example, we access one of these extension to gain access to the functions
|
|
|
+specifically needed for NativeScript.
|
|
|
+
|
|
|
A NativeScript behaves like any other script in Godot. Because the NativeScript
|
|
|
API is rather low level, it requires the library to specify many things more
|
|
|
verbosely than other scripting systems, such as GDScript. When a NativeScript
|
|
|
instance gets created, a library-given constructor gets called. When that
|
|
|
instance gets destroyed, the given destructor will be executed.
|
|
|
|
|
|
-These are forward declarations for the functions we'll be implementing for our
|
|
|
-object. A constructor and destructor is needed. Additionally, the object will
|
|
|
-have a single method called get_data.
|
|
|
-
|
|
|
.. code-block:: C
|
|
|
|
|
|
void *simple_constructor(godot_object *p_instance, void *p_method_data);
|
|
|
void simple_destructor(godot_object *p_instance, void *p_method_data, void *p_user_data);
|
|
|
- godot_variant simple_get_data(godot_object *p_instance, void *p_method_data
|
|
|
- , void *p_user_data, int p_num_args, godot_variant **p_args);
|
|
|
+ godot_variant simple_get_data(godot_object *p_instance, void *p_method_data,
|
|
|
+ void *p_user_data, int p_num_args, godot_variant **p_args);
|
|
|
+
|
|
|
+These are forward declarations for the functions we'll be implementing for our
|
|
|
+object. A constructor and destructor is needed. Additionally, the object will
|
|
|
+have a single method called ``get_data``.
|
|
|
|
|
|
Next up is the first of the entry points Godot will call when our dynamic
|
|
|
-library is loaded. These methods are all prefixed with Godot (you can change
|
|
|
-this later on) followed by their name. ``gdnative_init`` is a function that
|
|
|
-initialises our dynamic library. Godot will give it a pointer to a structure
|
|
|
-that contains various bits of information we may find useful amongst which the
|
|
|
-pointers to our API structures.
|
|
|
+library is loaded. These methods are all prefixed with ``godot_`` (you can
|
|
|
+change this later on) followed by their name. ``gdnative_init`` is a function
|
|
|
+that initializes our dynamic library. Godot will give it a pointer to a
|
|
|
+structure that contains various bits of information we may find useful among
|
|
|
+which the pointers to our API structures.
|
|
|
|
|
|
For any additional API structures we need to loop through our extensions array
|
|
|
and check the type of extension.
|
|
@@ -175,7 +193,7 @@ and check the type of extension.
|
|
|
void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *p_options) {
|
|
|
api = p_options->api_struct;
|
|
|
|
|
|
- // now find our extensions
|
|
|
+ // Now find our extensions.
|
|
|
for (int i = 0; i < api->num_extensions; i++) {
|
|
|
switch (api->extensions[i]->type) {
|
|
|
case GDNATIVE_EXT_NATIVESCRIPT: {
|
|
@@ -200,32 +218,7 @@ to clear our API pointers.
|
|
|
|
|
|
Finally we have ``nativescript_init`` which is the most important function we'll
|
|
|
need today. This function will be called by Godot as part of loading a GDNative
|
|
|
-library and communicates back to Godot what objects we make available to Godot.
|
|
|
-
|
|
|
-We first tell Godot which classes are implemented by calling
|
|
|
-``nativescript_register_class``. The first parameter here is the handle pointer
|
|
|
-given to us. The second is the name of our object class. The third is the type
|
|
|
-of object in Godot that we 'inherit' from, this is not true inheritance but it's
|
|
|
-close enough. Finally, our fourth and fifth parameters are descriptions for our
|
|
|
-constructor and destructor.
|
|
|
-
|
|
|
-We then tell Godot about our methods (well our one method in this case), by
|
|
|
-calling ``nativescript_register_method`` for each method of our class. In our
|
|
|
-case, that is just ``get_data``. Our first parameter is yet again our handle
|
|
|
-pointer. The second is again the name of the object class we're registering. The
|
|
|
-third is the name of our function as it will be known to GDScript. The fourth is
|
|
|
-our attributes setting. The fifth and final parameter is a description of which
|
|
|
-function to call when the method gets called.
|
|
|
-
|
|
|
-The descriptions contain the function pointers to the functions themselves. The
|
|
|
-other two fields in these structs are for specifying per-method userdata. The
|
|
|
-value in the ``method_data`` field will be passed on every function call as the
|
|
|
-``p_method_data`` argument. This is useful to reuse one function for different
|
|
|
-methods on possibly multiple different script-classes. If the ``method_data``
|
|
|
-value is a pointer to memory that needs to be freed, the ``free_func`` field can
|
|
|
-contain a pointer to a function that will free that memory. That free function
|
|
|
-gets called when the script itself (not instance!) gets unloaded (so usually at
|
|
|
-library-unload time).
|
|
|
+library and communicates back to the engine what objects we make available.
|
|
|
|
|
|
.. code-block:: C
|
|
|
|
|
@@ -236,18 +229,45 @@ library-unload time).
|
|
|
godot_instance_destroy_func destroy = { NULL, NULL, NULL };
|
|
|
destroy.destroy_func = &simple_destructor;
|
|
|
|
|
|
- nativescript_api->godot_nativescript_register_class(p_handle, "SIMPLE", "Reference",
|
|
|
- create, destroy);
|
|
|
+ nativescript_api->godot_nativescript_register_class(p_handle, "Simple", "Reference",
|
|
|
+ create, destroy);
|
|
|
|
|
|
godot_instance_method get_data = { NULL, NULL, NULL };
|
|
|
get_data.method = &simple_get_data;
|
|
|
|
|
|
godot_method_attributes attributes = { GODOT_METHOD_RPC_MODE_DISABLED };
|
|
|
|
|
|
- nativescript_api->godot_nativescript_register_method(p_handle, "SIMPLE", "get_data",
|
|
|
- attributes, get_data);
|
|
|
+ nativescript_api->godot_nativescript_register_method(p_handle, "Simple", "get_data",
|
|
|
+ attributes, get_data);
|
|
|
}
|
|
|
|
|
|
+We first tell the engine which classes are implemented by calling
|
|
|
+``nativescript_register_class``. The first parameter here is the handle pointer
|
|
|
+given to us. The second is the name of our object class. The third is the type
|
|
|
+of object in Godot that we 'inherit' from; this is not true inheritance but it's
|
|
|
+close enough. Finally, our fourth and fifth parameters are descriptions for our
|
|
|
+constructor and destructor.
|
|
|
+
|
|
|
+We then tell Godot about our methods (well our one method in this case), by
|
|
|
+calling ``nativescript_register_method`` for each method of our class. In our
|
|
|
+case, that is just ``get_data``. Our first parameter is yet again our handle
|
|
|
+pointer. The second is again the name of the object class we're registering. The
|
|
|
+third is the name of our function as it will be known to GDScript. The fourth is
|
|
|
+our attributes setting (see ``godot_method_rpc_mode`` enum in
|
|
|
+``godot_headers/nativescript/godot_nativescript.h`` for possible values). The
|
|
|
+fifth and final parameter is a description of which function to call when the
|
|
|
+method gets called.
|
|
|
+
|
|
|
+The description struct ``instance_method`` contains the function pointer to the
|
|
|
+function itself as first field. The other two fields in these structs are for
|
|
|
+specifying per-method userdata. The second is the ``method_data`` field which is
|
|
|
+passed on every function call as the ``p_method_data`` argument. This is useful
|
|
|
+to reuse one function for different methods on possibly multiple different
|
|
|
+script-classes. If the ``method_data`` value is a pointer to memory that needs
|
|
|
+to be freed, the third ``free_func`` field can contain a pointer to a function
|
|
|
+that will free that memory. That free function gets called when the script
|
|
|
+itself (not instance!) gets unloaded (so usually at library-unload time).
|
|
|
+
|
|
|
Now, it's time to start working on the functions of our object. First, we define
|
|
|
a structure that we use to store the member data of an instance of our GDNative
|
|
|
class.
|
|
@@ -286,33 +306,18 @@ instances' member data.
|
|
|
api->godot_free(p_user_data);
|
|
|
}
|
|
|
|
|
|
-And finally, we implement our get_data function. Data is always sent and
|
|
|
+And finally, we implement our ``get_data`` function. Data is always sent and
|
|
|
returned as variants so in order to return our data, which is a string, we first
|
|
|
need to convert our C string to a Godot string object, and then copy that string
|
|
|
object into the variant we are returning.
|
|
|
|
|
|
-Strings are heap-allocated in Godot, so they have a destructor which frees the
|
|
|
-memory. Destructors are named ``godot_TYPENAME_destroy``. When a Variant gets
|
|
|
-created with a String, it references the String. That means that the original
|
|
|
-String can be "destroyed" to decrease the ref-count. If that does not happen the
|
|
|
-String memory will leak since the ref-count will never be zero and the memory
|
|
|
-never deallocated. The returned variant gets automatically destroyed by Godot.
|
|
|
-
|
|
|
-(In more complex operations it can be confusing the keep track of which value
|
|
|
-needs to be deallocated and which does not. As a general rule: call
|
|
|
-godot_XXX_destroy when a C++ destructor would be called instead. The String
|
|
|
-destructor would be called in C++ after the Variant was created, so the same is
|
|
|
-necessary in C)
|
|
|
-
|
|
|
-The variant we return is destroyed automatically by Godot.
|
|
|
-
|
|
|
.. code-block:: C
|
|
|
|
|
|
godot_variant simple_get_data(godot_object *p_instance, void *p_method_data,
|
|
|
void *p_user_data, int p_num_args, godot_variant **p_args) {
|
|
|
godot_string data;
|
|
|
godot_variant ret;
|
|
|
- user_data_struct * user_data = (user_data_struct *) p_user_data;
|
|
|
+ user_data_struct *user_data = (user_data_struct *)p_user_data;
|
|
|
|
|
|
api->godot_string_new(&data);
|
|
|
api->godot_string_parse_utf8(&data, user_data->data);
|
|
@@ -322,172 +327,231 @@ The variant we return is destroyed automatically by Godot.
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-And that is the whole source code of our module.
|
|
|
+Strings are heap-allocated in Godot, so they have a destructor which frees the
|
|
|
+memory. Destructors are named ``godot_TYPENAME_destroy``. When a Variant gets
|
|
|
+created with a String, it references the String. That means that the original
|
|
|
+String can be "destroyed" to decrease the ref-count. If that does not happen the
|
|
|
+String memory will leak since the ref-count will never be zero and the memory
|
|
|
+never deallocated. The returned variant gets automatically destroyed by Godot.
|
|
|
+
|
|
|
+.. note::
|
|
|
+
|
|
|
+ In more complex operations it can be confusing the keep track of which value
|
|
|
+ needs to be deallocated and which does not. As a general rule: call
|
|
|
+ ``godot_TYPENAME_destroy`` when a C++ destructor would be called instead.
|
|
|
+ The String destructor would be called in C++ after the Variant was created,
|
|
|
+ so the same is necessary in C.
|
|
|
|
|
|
-If you add a blank ``.gdignore`` file to the src folder, Godot will not try to
|
|
|
-import the compiler-generated temporary files.
|
|
|
+The variant we return is destroyed automatically by Godot.
|
|
|
+
|
|
|
+And that is the whole source code of our module.
|
|
|
|
|
|
Compiling
|
|
|
---------
|
|
|
|
|
|
We now need to compile our source code. As mentioned our example project on
|
|
|
-GitHub contains a Scons configuration that does all the hard work for you but
|
|
|
+GitHub contains a SCons configuration that does all the hard work for you, but
|
|
|
for our tutorial here we are going to call the compilers directly.
|
|
|
|
|
|
-Assuming you are sticking to the folder structure suggested above it is best to
|
|
|
-CD into the src subfolder in a terminal session and execute the commands from
|
|
|
-there. Make sure to create the bin folder before you proceed.
|
|
|
+Assuming you are sticking to the folder structure suggested above, it is best to
|
|
|
+open a terminal session in the ``src`` folder and execute the commands from
|
|
|
+there. Make sure to create the ``bin`` folder before you proceed.
|
|
|
|
|
|
On Linux:
|
|
|
|
|
|
.. code-block:: none
|
|
|
|
|
|
- clang -std=c11 -fPIC -c -I/PATH/TO/GODOT/HEADERS simple.c -o simple.os
|
|
|
- clang -shared simple.os -o ../bin/libsimple.so
|
|
|
+ gcc -std=c11 -fPIC -c -I../../godot_headers simple.c -o simple.os
|
|
|
+ gcc -shared simple.os -o ../bin/libsimple.so
|
|
|
|
|
|
On macOS:
|
|
|
|
|
|
.. code-block:: none
|
|
|
|
|
|
- clang -std=c11 -fPIC -c -I/PATH/TO/GODOT/HEADERS simple.c -o simple.os -arch i386 -arch x86_64
|
|
|
- clang -dynamiclib simple.os -o ../bin/libsimple.dylib -arch i386 -arch x86_64
|
|
|
+ clang -std=c11 -fPIC -c -I../../godot_headers simple.c -o simple.os
|
|
|
+ clang -dynamiclib simple.os -o ../bin/libsimple.dylib
|
|
|
|
|
|
On Windows:
|
|
|
|
|
|
.. code-block:: none
|
|
|
|
|
|
- cl /Fosimple.obj /c simple.c /nologo -EHsc -DNDEBUG /MD /I. /IC:\PATH\TO\GODOT\HEADERS
|
|
|
+ cl /Fosimple.obj /c simple.c /nologo -EHsc -DNDEBUG /MD /I. /I..\..\godot_headers
|
|
|
link /nologo /dll /out:..\bin\libsimple.dll /implib:..\bin\libsimple.lib simple.obj
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
- on the Windows build you also end up with a libsimple.lib library. This is a
|
|
|
- library that you can compile into a project to provide access to the DLL. We
|
|
|
- get it as a bonus and we do not need it :) When exporting your game for
|
|
|
- release this file will be ignored.
|
|
|
+ On the Windows build you also end up with a ``libsimple.lib`` library. This
|
|
|
+ is a library that you can compile into a project to provide access to the
|
|
|
+ DLL. We get it as a byproduct and we do not need it :)
|
|
|
+ When exporting your game for release this file will be ignored.
|
|
|
|
|
|
-Creating our GDNLIB file
|
|
|
-------------------------
|
|
|
+.. tip::
|
|
|
|
|
|
-With our module compiled we now need to create a gdnlib file for our module
|
|
|
-which we place alongside our dynamic libraries. This file tells Godot what
|
|
|
-dynamic libraries are part of our module and need to be loaded per platform. At
|
|
|
-the time of writing this tutorial work is still being done on making this
|
|
|
-configurable from within Godot so for now grab your favourite text editor,
|
|
|
-create a file called libsimple.gdnlib and add the following into this file:
|
|
|
+ If you add a blank ``.gdignore`` file to the ``src`` folder, Godot will not
|
|
|
+ try to import the compiler-generated files. This is necessary on Windows
|
|
|
+ were compiled objects have the ``.obj`` extension, which is also a 3D model
|
|
|
+ format supported by the engine.
|
|
|
|
|
|
-.. code-block:: none
|
|
|
+Creating the GDNativeLibrary (``.gdnlib``) file
|
|
|
+-----------------------------------------------
|
|
|
|
|
|
- [general]
|
|
|
+With our module compiled, we now need to create a corresponding
|
|
|
+:ref:`GDNativeLibrary <class_GDNativeLibrary>` resource with ``.gdnlib``
|
|
|
+extension which we place alongside our dynamic libraries. This file tells Godot
|
|
|
+what dynamic libraries are part of our module and need to be loaded per
|
|
|
+platform.
|
|
|
|
|
|
- singleton=false
|
|
|
- load_once=true
|
|
|
- symbol_prefix="godot_"
|
|
|
+We can use Godot to generate this file, so open the "simple" project in the
|
|
|
+editor.
|
|
|
|
|
|
- [entry]
|
|
|
+Start by clicking the create resource button in the Inspector:
|
|
|
|
|
|
- X11.64="res://bin/libsimple.so"
|
|
|
- Windows.64="res://bin/libsimple.dll"
|
|
|
- OSX.64="res://bin/libsimple.dylib"
|
|
|
+.. image:: img/new_resource.gif
|
|
|
|
|
|
- [dependencies]
|
|
|
+And select ``GDNativeLibrary``:
|
|
|
+
|
|
|
+.. image:: img/gdnativelibrary_resource.png
|
|
|
|
|
|
- X11.64=[]
|
|
|
- Windows.64=[]
|
|
|
- OSX.64=[]
|
|
|
+You should see a contextual editor appear in the bottom panel. Use the "Expand
|
|
|
+Bottom Panel" button in the bottom right to expand it to full height:
|
|
|
|
|
|
-This file contains 3 sections.
|
|
|
+.. image:: img/gdnativelibrary_editor.png
|
|
|
|
|
|
-The **general** section contains some info that tells Godot how to use our
|
|
|
-module.
|
|
|
+General properties
|
|
|
+~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-If singleton is true our library is automatically loaded and a function called
|
|
|
-godot_singleton_init is called. We'll leave that for another tutorial.
|
|
|
+In the Inspector, you have various properties to control loading the library.
|
|
|
|
|
|
-If load_once is true our library is loaded only once and each individual script
|
|
|
-that uses our library will use the same data. Any variable you define globally
|
|
|
-will be accessible from any instance of your object you create. If load_once is
|
|
|
-false a new copy of the library is loaded into memory each time a script access
|
|
|
-the library.
|
|
|
+If *Load Once* is enabled, our library is loaded only once and each individual
|
|
|
+script that uses our library will use the same data. Any variable you define
|
|
|
+globally will be accessible from any instance of your object you create. If
|
|
|
+*Load Once* is disabled, a new copy of the library is loaded into memory each
|
|
|
+time a script accesses the library.
|
|
|
|
|
|
-The symbol_prefix is a prefix for our core functions. So the Godot in
|
|
|
-godot_nativescript_init for instance. If you use multiple GDnative libraries
|
|
|
-that you wish to statically link you'll have to use different prefixes. This
|
|
|
+If *Singleton* is enabled, our library is automatically loaded and a function
|
|
|
+called ``godot_singleton_init`` is called. We'll leave that for another
|
|
|
+tutorial.
|
|
|
+
|
|
|
+The *Symbol Prefix* is a prefix for our core functions, such as ``godot_`` in
|
|
|
+``godot_nativescript_init`` seen earlier. If you use multiple GDNative libraries
|
|
|
+that you wish to statically link, you will have to use different prefixes. This
|
|
|
again is a subject to dive into deeper in a separate tutorial, it is only needed
|
|
|
at this time for deployment to iOS as this platform does not like dynamic
|
|
|
libraries.
|
|
|
|
|
|
-The **entry** section tells us for each platform and feature combination which
|
|
|
-dynamic library has to be loaded. This also informs the exporter which files
|
|
|
-need to be exported when exporting to a specific platform.
|
|
|
+*Reloadable* defines whether the library should be reloaded when the editor
|
|
|
+loses and gains focus, typically to pick up new or modified symbols from any
|
|
|
+change made to the library externally.
|
|
|
|
|
|
-The **dependencies** section tells Godot what other files need to be exported
|
|
|
-for each platform in order for our library to work. Say that your GDNative
|
|
|
-module uses another DLL to implement functionality from a 3rd party library,
|
|
|
-this is where you list that DLL.
|
|
|
+Platform libraries
|
|
|
+~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-Putting it all together
|
|
|
------------------------
|
|
|
+The GDNativeLibrary editor plugin lets you configure two things for each
|
|
|
+platform and architecture that you aim to support.
|
|
|
|
|
|
-Now that we should have a working GDNative library it is time to fire up Godot
|
|
|
-and use it. Open up the sample project if you haven't left it open after
|
|
|
-creating the project all the way at the beginning of this tutorial.
|
|
|
+The *Dynamic Library* column (``entry`` section in the saved file) tells us for
|
|
|
+each platform and feature combination which dynamic library has to be loaded.
|
|
|
+This also informs the exporter which files need to be exported when exporting to
|
|
|
+a specific platform.
|
|
|
|
|
|
-Creating our GDNS file
|
|
|
-----------------------
|
|
|
+The *Dependencies* column (also ``dependencies`` section) tells Godot what other
|
|
|
+files need to be exported for each platform in order for our library to work.
|
|
|
+Say that your GDNative module uses another DLL to implement functionality from a
|
|
|
+3rd party library, this is where you list that DLL.
|
|
|
|
|
|
-With our GDNLIB file we've told Godot how to load our library, now we need to
|
|
|
-tell it about our "Simple" object class. This we do by creating a GDNS resource
|
|
|
-file.
|
|
|
+For our example, we only built libraries for Linux, macOS and/or Windows, so you
|
|
|
+can link them in the relevant fields by clicking the folder button. If you built
|
|
|
+all three libraries, you should have something like this:
|
|
|
|
|
|
-Start by clicking the create resource button in the Inspector:
|
|
|
+.. image:: img/gdnativelibrary_complete.png
|
|
|
|
|
|
-.. image:: img/new_resource.gif
|
|
|
+Saving the resource
|
|
|
+~~~~~~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+We can then save our GDNativeLibrary resource as ``bin/libsimple.gdnlib`` with
|
|
|
+the Save button in the Inspector:
|
|
|
+
|
|
|
+.. image:: img/gdnativelibrary_save.png
|
|
|
+
|
|
|
+The file is saved in a text-based format and should have contents similar to
|
|
|
+this:
|
|
|
+
|
|
|
+.. code-block:: none
|
|
|
+
|
|
|
+ [general]
|
|
|
+
|
|
|
+ singleton=false
|
|
|
+ load_once=true
|
|
|
+ symbol_prefix="godot_"
|
|
|
+ reloadable=true
|
|
|
+
|
|
|
+ [entry]
|
|
|
+
|
|
|
+ OSX.64="res://bin/libsimple.dylib"
|
|
|
+ OSX.32="res://bin/libsimple.dylib"
|
|
|
+ Windows.64="res://bin/libsimple.dll"
|
|
|
+ X11.64="res://bin/libsimple.so"
|
|
|
+
|
|
|
+ [dependencies]
|
|
|
+
|
|
|
+ OSX.64=[ ]
|
|
|
+ OSX.32=[ ]
|
|
|
+ Windows.64=[ ]
|
|
|
+ X11.64=[ ]
|
|
|
+
|
|
|
+Creating the NativeScript (``.gdns``) file
|
|
|
+------------------------------------------
|
|
|
+
|
|
|
+With our ``.gdnlib`` file we've told Godot how to load our library, now we need
|
|
|
+to tell it about our "Simple" object class. We do this by creating a
|
|
|
+:ref:`NativeScript <class_NativeScript>` resource file with ``.gdns`` extension.
|
|
|
|
|
|
-And select NativeScript:
|
|
|
+Like done for the GDNativeLibrary resource, click the button to create a new
|
|
|
+resource in the Inspector and select ``NativeScript``:
|
|
|
|
|
|
.. image:: img/nativescript_resource.png
|
|
|
|
|
|
-Press Create, now the inspector will show a few fields we need to enter. In
|
|
|
-Class Name we enter "SIMPLE" which is the object class name we used in our C
|
|
|
-source when calling godot_nativescript_register_class. We also need to select
|
|
|
-our GDNLIB file by clicking on Library and selecting Load:
|
|
|
+The inspector will show a few properties that we need to fill. As *Class Name*
|
|
|
+we enter "Simple" which is the object class name that we declared in our C
|
|
|
+source when calling ``godot_nativescript_register_class``. We also need to
|
|
|
+select our ``.gdnlib`` file by clicking on *Library* and selecting *Load*:
|
|
|
|
|
|
.. image:: img/nativescript_library.png
|
|
|
|
|
|
-Finally click on the save icon and save this as bin/simple.gdns:
|
|
|
+Finally click on the save icon and save this as ``bin/simple.gdns``:
|
|
|
|
|
|
.. image:: img/save_gdns.gif
|
|
|
|
|
|
-Now it's time to build our scene. Add a control node to your scene as your root
|
|
|
-and call it main. Then add a button and a label as subnodes. Place them
|
|
|
+Now it's time to build our scene. Add a Control node to your scene as your root
|
|
|
+and call it ``main``. Then add a Button and a Label as child nodes. Place them
|
|
|
somewhere nice on screen and give your button a name.
|
|
|
|
|
|
.. image:: img/c_main_scene_layout.png
|
|
|
|
|
|
-Select the control node and create a script for the control node:
|
|
|
+Select the control node and attach a script to it:
|
|
|
|
|
|
.. image:: img/add_main_script.gif
|
|
|
|
|
|
-Next link up the pressed signal on the button to your script:
|
|
|
+Next link up the ``pressed`` signal on the button to your script:
|
|
|
|
|
|
.. image:: img/connect_button_signal.gif
|
|
|
|
|
|
-Don't forget to save your scene, call it main.tscn.
|
|
|
+Don't forget to save your scene, call it ``main.tscn``.
|
|
|
|
|
|
-Now we can implement our main.gd code:
|
|
|
+Now we can implement our ``main.gd`` code:
|
|
|
|
|
|
::
|
|
|
|
|
|
extends Control
|
|
|
|
|
|
- # load the SIMPLE library
|
|
|
+ # load the Simple library
|
|
|
onready var data = preload("res://bin/simple.gdns").new()
|
|
|
|
|
|
func _on_Button_pressed():
|
|
|
$Label.text = "Data = " + data.get_data()
|
|
|
|
|
|
After all that, our project should work. The first time you run it Godot will
|
|
|
-ask you what your main scene is and you select your main.tscn file and presto:
|
|
|
+ask you what your main scene is and you select your ``main.tscn`` file and
|
|
|
+presto:
|
|
|
|
|
|
.. image:: img/c_sample_result.png
|