diff --git a/tutorials/scripting/gdextension/files/cpp_example/SConstruct b/tutorials/scripting/gdextension/files/cpp_example/SConstruct index bde48c26fa35..3a7b5aad667b 100644 --- a/tutorials/scripting/gdextension/files/cpp_example/SConstruct +++ b/tutorials/scripting/gdextension/files/cpp_example/SConstruct @@ -1,41 +1,8 @@ -#!python +#!/usr/bin/env python import os +import sys -opts = Variables([], ARGUMENTS) - -# Gets the standard flags CC, CCX, etc. -env = DefaultEnvironment() - -# Define our options -opts.Add(EnumVariable('target', "Compilation target", 'debug', ['d', 'debug', 'r', 'release'])) -opts.Add(EnumVariable('platform', "Compilation platform", '', ['', 'windows', 'linuxbsd', 'linux', 'osx'])) -opts.Add(EnumVariable('p', "Compilation target, alias for 'platform'", '', ['', 'windows', 'linuxbsd', 'linux', 'osx'])) -opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no')) -opts.Add(PathVariable('target_path', 'The path where the lib is installed.', 'demo/bin/')) -opts.Add(PathVariable('target_name', 'The library name.', 'libgdexample', PathVariable.PathAccept)) - -# Local dependency paths, adapt them to your setup -godot_headers_path = "godot-cpp/godot-headers/" -cpp_bindings_path = "godot-cpp/" -cpp_library = "libgodot-cpp" - -# only support 64 at this time.. -bits = 64 - -# Updates the environment with the option variables. -opts.Update(env) - -# Process some arguments -if env['use_llvm']: - env['CC'] = 'clang' - env['CXX'] = 'clang++' - -if env['p'] != '': - env['platform'] = env['p'] - -if env['platform'] == '': - print("No valid target platform selected.") - quit() +env = SConscript("godot-cpp/SConstruct") # For the reference: # - CCFLAGS are compilation flags shared between C and C++ @@ -45,65 +12,26 @@ if env['platform'] == '': # - CPPDEFINES are for pre-processor defines # - LINKFLAGS are for linking flags -# Check our platform specifics -if env['platform'] == "osx": - env['target_path'] += 'osx/' - cpp_library += '.osx' - env.Append(CCFLAGS=['-arch', 'x86_64']) - env.Append(CXXFLAGS=['-std=c++17']) - env.Append(LINKFLAGS=['-arch', 'x86_64']) - if env['target'] in ('debug', 'd'): - env.Append(CCFLAGS=['-g', '-O2']) - else: - env.Append(CCFLAGS=['-g', '-O3']) - -elif env['platform'] in ('linuxbsd', 'linux'): - env['target_path'] += 'linuxbsd/' - cpp_library += '.linux' - env.Append(CCFLAGS=['-fPIC']) - env.Append(CXXFLAGS=['-std=c++17']) - if env['target'] in ('debug', 'd'): - env.Append(CCFLAGS=['-g3', '-Og']) - else: - env.Append(CCFLAGS=['-g', '-O3']) - -elif env['platform'] == "windows": - env['target_path'] += 'win64/' - cpp_library += '.windows' - # This makes sure to keep the session environment variables on windows, - # that way you can run scons in a vs 2017 prompt and it will find all the required tools - env.Append(ENV=os.environ) - - env.Append(CPPDEFINES=['WIN32', '_WIN32', '_WINDOWS', '_CRT_SECURE_NO_WARNINGS']) - env.Append(CCFLAGS=['-W3', '-GR']) - env.Append(CXXFLAGS='/std:c++17') - if env['target'] in ('debug', 'd'): - env.Append(CPPDEFINES=['_DEBUG']) - env.Append(CCFLAGS=['-EHsc', '-MDd', '-ZI']) - env.Append(LINKFLAGS=['-DEBUG']) - else: - env.Append(CPPDEFINES=['NDEBUG']) - env.Append(CCFLAGS=['-O2', '-EHsc', '-MD']) - -if env['target'] in ('debug', 'd'): - cpp_library += '.debug' -else: - cpp_library += '.release' - -cpp_library += '.' + str(bits) - -# make sure our binding library is properly includes -env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/']) -env.Append(LIBPATH=[cpp_bindings_path + 'bin/']) -env.Append(LIBS=[cpp_library]) - # tweak this if you want to use different folders, or more folders, to store your source code in. -env.Append(CPPPATH=['src/']) -sources = Glob('src/*.cpp') - -library = env.SharedLibrary(target=env['target_path'] + env['target_name'] , source=sources) +env.Append(CPPPATH=["src/"]) +sources = Glob("src/*.cpp") + +if env["platform"] == "macos": + library = env.SharedLibrary( + "demo/bin/osx/libgdexample.{}.framework".format( + env["platform"], + ), + source=sources, + ) +elif env["platform"] == "windows": + library = env.SharedLibrary( + "demo/bin/win64/libgdexample.{}.{}{}".format(env["platform"], env["arch"], env["SHLIBSUFFIX"]), + source=sources, + ) +else: + library = env.SharedLibrary( + "demo/bin/linux/libgdexample.{}.{}{}".format(env["platform"], env["arch"], env["SHLIBSUFFIX"]), + source=sources, + ) Default(library) - -# Generates help for the -h scons option. -Help(opts.GenerateHelpText(env)) diff --git a/tutorials/scripting/gdextension/gdextension_cpp_example.rst b/tutorials/scripting/gdextension/gdextension_cpp_example.rst index 824a4026d7e9..3d8d0dce88b9 100644 --- a/tutorials/scripting/gdextension/gdextension_cpp_example.rst +++ b/tutorials/scripting/gdextension/gdextension_cpp_example.rst @@ -155,7 +155,7 @@ GDExtension node we'll be creating. We will name it ``gdexample.h``: namespace godot { class GDExample : public Sprite2D { - GD_CLASS(GDExample, Sprite2D) + GDCLASS(GDExample, Sprite2D) private: float time_passed; @@ -370,7 +370,6 @@ also result in *just* that file being exported when you export the project, which means the data pack won't contain libraries that are incompatible with the target platform. -TODO: check if dependencies section is supported Finally, the ``dependencies`` section allows you to name additional dynamic libraries that should be included as well. This is important when your GDExtension plugin implements someone else's library and requires you to supply a @@ -394,20 +393,15 @@ Adding properties ----------------- GDScript allows you to add properties to your script using the ``export`` -keyword. In GDExtension you have to register the properties and there are two ways -of doing this. You can either bind directly to a member or use a setter and -getter function. +keyword. In GDExtension you have to register the properties with a getter and +sett function or directly implement the ``_get_property_list``, ``_get`` and +``_set`` methods of an object (but that goes far beyond the scope of this +tutorial. -.. note:: - - There is a third option, just like in GDScript you can directly implement the - ``_get_property_list``, ``_get`` and ``_set`` methods of an object but that - goes far beyond the scope of this tutorial. - -We'll examine both starting with the direct bind. Lets add a property that -allows us to control the amplitude of our wave. +Lets add a property that allows us to control the amplitude of our wave. -In our ``gdexample.h`` file we simply need to add a member variable like so: +In our ``gdexample.h`` file we need to add a member variable and getter and setter +functions: .. code-block:: C++ @@ -415,6 +409,10 @@ In our ``gdexample.h`` file we simply need to add a member variable like so: private: float time_passed; float amplitude; + + public: + void set_amplitude(const float amplitude); + float get_amplitude() const; ... In our ``gdexample.cpp`` file we need to make a number of changes, we will only @@ -422,12 +420,14 @@ show the methods we end up changing, don't remove the lines we're omitting: .. code-block:: C++ - void GDExample::_register_methods() { - register_method("_process", &GDExample::_process); - register_property("amplitude", &GDExample::amplitude, 10.0); + void GDExample::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_amplitude"), &GDExample::get_amplitude); + ClassDB::bind_method(D_METHOD("set_amplitude", "p_amplitude"), &GDExample::set_amplitude); + + ClassDB::add_property("GDExample", PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude"); } - void GDExample::_init() { + void GDExample::GDExample() { // initialize any variables here time_passed = 0.0; amplitude = 10.0; @@ -444,21 +444,19 @@ show the methods we end up changing, don't remove the lines we're omitting: set_position(new_position); } + void GDExample::set_amplitude(const float p_amplitude) { + amplitude = p_amplitude; + } + + float GDExample::get_amplitude() const { + return amplitude; + } + Once you compile the module with these changes in place, you will see that a property has been added to our interface. You can now change this property and when you run your project, you will see that our Godot icon travels along a larger figure. -.. note:: - - The ``reloadable`` property in the ``gdexample.gdnlib`` file must be set to - ``true`` for the Godot editor to automatically pick up the newly added - property. - - However, this setting should be used with care, especially when tool classes - are used, as the editor might hold objects then that have script instances - attached to them that are managed by a GDExtension library. - Let's do the same but for the speed of our animation and use a setter and getter function. Our ``gdexample.h`` header file again only needs a few more lines of code: @@ -479,13 +477,13 @@ showing the methods that have changed so don't remove anything we're omitting: .. code-block:: C++ - void GDExample::_register_methods() { - register_method("_process", &GDExample::_process); - register_property("amplitude", &GDExample::amplitude, 10.0); - register_property("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0); + void GDExample::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_speed"), &GDExample::get_speed); + ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &GDExample::set_speed); + ClassDB::add_property("GDExample", PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed"); } - void GDExample::_init() { + void GDExample::GDExample() { // initialize any variables here time_passed = 0.0; amplitude = 10.0; @@ -507,7 +505,7 @@ showing the methods that have changed so don't remove anything we're omitting: speed = p_speed; } - float GDExample::get_speed() { + float GDExample::get_speed() const { return speed; } @@ -524,14 +522,10 @@ need to make additional choices based on the state of your object. .. note:: For simplicity, we've left out the optional parameters in the - register_property method call. These parameters are - ``rpc_mode``, ``usage``, ``hint`` and ``hint_string``. These can be used to + add_property() method call. These parameters are + ``hint``, ``hint_string``, ``usage`` and ``class_name``. These can be used to further configure how properties are displayed and set on the Godot side. - Modern C++ compilers are able to infer the class and variable type and allow - you to omit the ```` part of our ``register_property`` - method. We've had mixed experiences with this however. - Signals -------