123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- .. _doc_gdnative_c_example:
- GDNative C example
- ==================
- 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
- 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
- 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.
- :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
- GDScript:
- ::
- extends Reference
- var data
- func _ready():
- data = "World from 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.
- Prerequisites
- -------------
- 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
- 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:
- .. code-block:: none
- git clone https://github.com/GodotNativeTools/godot_headers
- This will download the required files into that folder.
- .. 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 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 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:
- .. code-block:: none
- git clone https://github.com/GodotNativeTools/godot_headers -b 3.0
- If you are building Godot from source with your own changes that impact
- GDNative, you can find the updated class and structure definition in
- ``<godotsource>/modules/gdnative/include``
- 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:
- .. code-block:: none
- + <your development folder>
- + godot_headers
- - <lots of files here>
- + simple
- + bin
- - libsimple.dll/so/dylib
- - libsimple.gdnlib
- - simple.gdns
- + src
- - .gdignore
- - simple.c
- 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.
- 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
- 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.
- .. 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;
- 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);
- 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.
- For any additional API structures we need to loop through our extensions array
- and check the type of extension.
- .. code-block:: C
- void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *p_options) {
- api = p_options->api_struct;
- // now find our extensions
- for (int i = 0; i < api->num_extensions; i++) {
- switch (api->extensions[i]->type) {
- case GDNATIVE_EXT_NATIVESCRIPT: {
- nativescript_api = (godot_gdnative_ext_nativescript_api_struct *)api->extensions[i];
- }; break;
- default: break;
- }
- }
- }
- Next up is ``gdnative_terminate`` which is called before the library is
- unloaded. Godot will unload the library when no object uses it anymore. Here,
- you can do any cleanup you may need to do. For our example, we're simply going
- to clear our API pointers.
- .. code-block:: C
- void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *p_options) {
- api = NULL;
- nativescript_api = NULL;
- }
- 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).
- .. code-block:: C
- void GDN_EXPORT godot_nativescript_init(void *p_handle) {
- godot_instance_create_func create = { NULL, NULL, NULL };
- create.create_func = &simple_constructor;
- 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);
- 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);
- }
- 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.
- .. code-block:: C
- typedef struct user_data_struct {
- char data[256];
- } user_data_struct;
- And then, we define our constructor. All we do in our constructor is allocate
- memory for our structure and fill it with some data. Note that we use Godot's
- memory functions so the memory gets tracked and then return the pointer to our
- new structure. This pointer will act as our instance identifier in case multiple
- objects are instantiated.
- This pointer will be passed to any of our functions related to our object as a
- parameter called ``p_user_data``, and can both be used to identify our instance
- and to access its member data.
- .. code-block:: C
- void *simple_constructor(godot_object *p_instance, void *p_method_data) {
- user_data_struct *user_data = api->godot_alloc(sizeof(user_data_struct));
- strcpy(user_data->data, "World from GDNative!");
- return user_data;
- }
- Our destructor is called when Godot is done with our object and we free our
- instances' member data.
- .. code-block:: C
- void simple_destructor(godot_object *p_instance, void *p_method_data, void *p_user_data) {
- api->godot_free(p_user_data);
- }
- 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;
- api->godot_string_new(&data);
- api->godot_string_parse_utf8(&data, user_data->data);
- api->godot_variant_new_string(&ret, &data);
- api->godot_string_destroy(&data);
- return ret;
- }
- And that is the whole source code of our module.
- If you add a blank ``.gdignore`` file to the src folder, Godot will not try to
- import the compiler-generated temporary files.
- 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
- 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.
- 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
- 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
- On Windows:
- .. code-block:: none
- cl /Fosimple.obj /c simple.c /nologo -EHsc -DNDEBUG /MD /I. /IC:\PATH\TO\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.
- Creating our GDNLIB file
- ------------------------
- 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:
- .. code-block:: none
- [general]
- singleton=false
- load_once=true
- symbol_prefix="godot_"
- [entry]
- X11.64="res://bin/libsimple.so"
- Windows.64="res://bin/libsimple.dll"
- OSX.64="res://bin/libsimple.dylib"
- [dependencies]
- X11.64=[]
- Windows.64=[]
- OSX.64=[]
- This file contains 3 sections.
- The **general** section contains some info that tells Godot how to use our
- module.
- 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.
- 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.
- 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
- 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.
- 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.
- Putting it all together
- -----------------------
- 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.
- Creating our 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. This we do by creating a GDNS resource
- file.
- Start by clicking the create resource button in the Inspector:
- .. image:: img/new_resource.gif
- 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:
- .. image:: img/nativescript_library.png
- 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
- 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:
- .. image:: img/add_main_script.gif
- 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.
- Now we can implement our main.gd code:
- ::
- extends Control
- # 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:
- .. image:: img/c_sample_result.png
|