From b3a4a2cf9360cad559d11eeab8940c1cfc0b32d0 Mon Sep 17 00:00:00 2001 From: George Marques Date: Thu, 19 Aug 2021 14:51:41 -0300 Subject: [PATCH] Add sample test project --- .gitignore | 1 + test/SConstruct | 140 ++++++++++++++++++------------------ test/default_env.tres | 7 ++ test/example.gdextension | 7 ++ test/icon.png | Bin 0 -> 3305 bytes test/icon.png.import | 35 +++++++++ test/main.gd | 26 +++++++ test/main.tscn | 31 ++++++++ test/project.godot | 23 ++++++ test/src/example.cpp | 91 +++++++++++++++++++++++ test/src/example.h | 50 +++++++++++++ test/src/register_types.cpp | 40 +++++++++++ test/src/register_types.h | 7 ++ 13 files changed, 388 insertions(+), 70 deletions(-) create mode 100644 test/default_env.tres create mode 100644 test/example.gdextension create mode 100644 test/icon.png create mode 100644 test/icon.png.import create mode 100644 test/main.gd create mode 100644 test/main.tscn create mode 100644 test/project.godot create mode 100644 test/src/example.cpp create mode 100644 test/src/example.h create mode 100644 test/src/register_types.cpp create mode 100644 test/src/register_types.h diff --git a/.gitignore b/.gitignore index 2782c5c1..ae7705d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Godot auto generated files *.gen.* .import/ +.godot/ /gen/ # Misc diff --git a/test/SConstruct b/test/SConstruct index a3423137..b9d13209 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -4,33 +4,32 @@ import sys # Try to detect the host platform automatically. # This is used if no `platform` argument is passed -if sys.platform.startswith('linux'): - host_platform = 'linux' -elif sys.platform == 'darwin': - host_platform = 'osx' -elif sys.platform == 'win32' or sys.platform == 'msys': - host_platform = 'windows' +if sys.platform.startswith("linux"): + host_platform = "linux" +elif sys.platform == "darwin": + host_platform = "osx" +elif sys.platform == "win32" or sys.platform == "msys": + host_platform = "windows" else: - raise ValueError( - 'Could not detect platform automatically, please specify with ' - 'platform=' - ) + raise ValueError("Could not detect platform automatically, please specify with " "platform=") -env = Environment(ENV = os.environ) +env = Environment(ENV=os.environ) opts = Variables([], ARGUMENTS) # Define our options -opts.Add(EnumVariable('target', "Compilation target", 'debug', ['d', 'debug', 'r', 'release'])) -opts.Add(EnumVariable('platform', "Compilation platform", host_platform, ['', 'windows', 'x11', 'linux', 'osx'])) -opts.Add(EnumVariable('p', "Compilation target, alias for 'platform'", host_platform, ['', 'windows', 'x11', 'linux', 'osx'])) -opts.Add(EnumVariable('bits', 'Target platform bits', '64', ('32', '64'))) -opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no')) -opts.Add(PathVariable('target_path', 'The path where the lib is installed.', 'bin/', PathVariable.PathAccept)) -opts.Add(PathVariable('target_name', 'The library name.', 'libgdexample', PathVariable.PathAccept)) +opts.Add(EnumVariable("target", "Compilation target", "debug", ["d", "debug", "r", "release"])) +opts.Add(EnumVariable("platform", "Compilation platform", host_platform, ["", "windows", "x11", "linux", "osx"])) +opts.Add( + EnumVariable("p", "Compilation target, alias for 'platform'", host_platform, ["", "windows", "x11", "linux", "osx"]) +) +opts.Add(EnumVariable("bits", "Target platform bits", "64", ("32", "64"))) +opts.Add(BoolVariable("use_llvm", "Use the LLVM / Clang compiler", "no")) +opts.Add(PathVariable("target_path", "The path where the lib is installed.", "bin/", PathVariable.PathAccept)) +opts.Add(PathVariable("target_name", "The library name.", "libgdexample", PathVariable.PathAccept)) # Local dependency paths, adapt them to your setup -godot_headers_path = "../godot-headers/" +godot_headers_path = "../godot-headers-temp/" cpp_bindings_path = "../" cpp_library = "libgodot-cpp" @@ -45,25 +44,25 @@ Help(opts.GenerateHelpText(env)) # This makes sure to keep the session environment variables on Windows. # This way, you can run SCons in a Visual Studio 2017 prompt and it will find # all the required tools -if host_platform == 'windows' and env['platform'] != 'android': - if env['bits'] == '64': - env = Environment(TARGET_ARCH='amd64') - elif env['bits'] == '32': - env = Environment(TARGET_ARCH='x86') +if host_platform == "windows" and env["platform"] != "android": + if env["bits"] == "64": + env = Environment(TARGET_ARCH="amd64") + elif env["bits"] == "32": + env = Environment(TARGET_ARCH="x86") opts.Update(env) # Process some arguments -if env['use_llvm']: - env['CC'] = 'clang' - env['CXX'] = 'clang++' +if env["use_llvm"]: + env["CC"] = "clang" + env["CXX"] = "clang++" -if env['p'] != '': - env['platform'] = env['p'] +if env["p"] != "": + env["platform"] = env["p"] -if env['platform'] == '': +if env["platform"] == "": print("No valid target platform selected.") - quit(); + quit() # For the reference: # - CCFLAGS are compilation flags shared between C and C++ @@ -73,63 +72,64 @@ if env['platform'] == '': # - CPPDEFINES are for pre-processor defines # - LINKFLAGS are for linking flags +if env["target"] == "debug": + env.Append(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_METHODS_ENABLED"]) + # 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']) +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']) + env.Append(CCFLAGS=["-g", "-O3"]) -elif env['platform'] in ('x11', 'linux'): - env['target_path'] += 'x11/' - cpp_library += '.linux' - env.Append(CCFLAGS=['-fPIC']) - env.Append(CXXFLAGS=['-std=c++17']) - if env['target'] in ('debug', 'd'): - env.Append(CCFLAGS=['-g3', '-Og']) +elif env["platform"] in ("x11", "linux"): + env["target_path"] += "x11/" + 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']) + env.Append(CCFLAGS=["-g", "-O3"]) -elif env['platform'] == "windows": - env['target_path'] += 'win64/' - cpp_library += '.windows' +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']) + env.Append(CPPDEFINES=["WIN32", "_WIN32", "_WINDOWS", "_CRT_SECURE_NO_WARNINGS"]) + env.Append(CCFLAGS=["-W3", "-GR"]) + 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']) + env.Append(CPPDEFINES=["NDEBUG"]) + env.Append(CCFLAGS=["-O2", "-EHsc", "-MD"]) -if env['target'] in ('debug', 'd'): - cpp_library += '.debug' +if env["target"] in ("debug", "d"): + cpp_library += ".debug" else: - cpp_library += '.release' + cpp_library += ".release" -cpp_library += '.' + str(bits) +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(CPPPATH=[".", godot_headers_path, cpp_bindings_path + "include/", cpp_bindings_path + "gen/include/"]) +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') +env.Append(CPPPATH=["src/"]) +sources = Glob("src/*.cpp") -library = env.SharedLibrary(target=env['target_path'] + env['target_name'] , source=sources) +library = env.SharedLibrary(target=env["target_path"] + env["target_name"], source=sources) Default(library) - diff --git a/test/default_env.tres b/test/default_env.tres new file mode 100644 index 00000000..770cd853 --- /dev/null +++ b/test/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=3 uid="uid://dtd3q2x2ulcsi"] + +[sub_resource type="Sky" id="1"] + +[resource] +background_mode = 2 +sky = SubResource( "1" ) diff --git a/test/example.gdextension b/test/example.gdextension new file mode 100644 index 00000000..491d38d9 --- /dev/null +++ b/test/example.gdextension @@ -0,0 +1,7 @@ +[configuration] + +entry_symbol = "example_library_init" + +[libraries] + +Linux.64 = "bin/x11/libgdexample.so" diff --git a/test/icon.png b/test/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c98fbb601c83c81ec8c22b1dba7d1d57c62b323c GIT binary patch literal 3305 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 literal 0 HcmV?d00001 diff --git a/test/icon.png.import b/test/icon.png.import new file mode 100644 index 00000000..fc6df247 --- /dev/null +++ b/test/icon.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture2D" +uid="uid://cswr8vy4lt7dt" +path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +compress/normal_map=0 +compress/channel_pack=0 +compress/streamed=false +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/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 diff --git a/test/main.gd b/test/main.gd new file mode 100644 index 00000000..ca3a7dd4 --- /dev/null +++ b/test/main.gd @@ -0,0 +1,26 @@ +extends Node + +func _ready(): + # Connect signals. + $Button.button_up.connect($Example.emit_custom_signal, ["Button", 42]) + $Example.custom_signal.connect(on_signal) + + # Call methods. + $Example.simple_func() + ($Example as Example).simple_const_func() # Force use of ptrcall + prints("returned", $Example.return_something("some string")) + prints("returned const", $Example.return_something_const()) + prints("vararg args", $Example.varargs_func("some", "arguments", "to", "test")) + + # Use properties. + prints("custom postion is", $Example.custom_position) + $Example.custom_position = Vector2(50, 50) + prints("custom postion now is", $Example.custom_position) + + # Get constants + prints("FIRST", $Example.FIRST) + prints("ANSWER_TO_EVERYTHING", $Example.ANSWER_TO_EVERYTHING) + prints("CONSTANT_WITHOUT_ENUM", $Example.CONSTANT_WITHOUT_ENUM) + +func on_signal(name, value): + prints("Example emitted:", name, value) diff --git a/test/main.tscn b/test/main.tscn new file mode 100644 index 00000000..23b2799f --- /dev/null +++ b/test/main.tscn @@ -0,0 +1,31 @@ +[gd_scene load_steps=2 format=3 uid="uid://dmx2xuigcpvt4"] + +[ext_resource type="Script" path="res://main.gd" id="1_c326s"] + +[node name="Node" type="Node"] +script = ExtResource( "1_c326s" ) + +[node name="Example" type="Example" parent="."] +offset_right = 40.0 +offset_bottom = 40.0 +script = null +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="Example"] +offset_left = 194.0 +offset_top = -2.0 +offset_right = 234.0 +offset_bottom = 21.0 +structured_text_bidi_override_options = [] +script = null + +[node name="Button" type="Button" parent="."] +offset_right = 79.0 +offset_bottom = 29.0 +text = "Click me!" +script = null +__meta__ = { +"_edit_use_anchors_": false +} diff --git a/test/project.godot b/test/project.godot new file mode 100644 index 00000000..d1c7331f --- /dev/null +++ b/test/project.godot @@ -0,0 +1,23 @@ +; 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=4 + +[application] + +config/name="GDExtension Test Project" +run/main_scene="res://main.tscn" +config/icon="res://icon.png" + +[native_extensions] + +paths=["res://example.gdextension"] + +[rendering] + +environment/defaults/default_environment="res://default_env.tres" diff --git a/test/src/example.cpp b/test/src/example.cpp new file mode 100644 index 00000000..27be6a1c --- /dev/null +++ b/test/src/example.cpp @@ -0,0 +1,91 @@ +#include "example.h" + +#include + +#include +#include +#include + +using namespace godot; + +void Example::_bind_methods() { + // Methods. + ClassDB::bind_method(D_METHOD("simple_func"), &Example::simple_func); + ClassDB::bind_method(D_METHOD("simple_const_func"), &Example::simple_const_func); + ClassDB::bind_method(D_METHOD("return_something"), &Example::return_something); + ClassDB::bind_method(D_METHOD("return_something_const"), &Example::return_something_const); + + { + MethodInfo mi; + mi.arguments.push_back(PropertyInfo(Variant::STRING, "some_argument")); + mi.name = "varargs_func"; + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "varargs_func", &Example::varargs_func, mi); + } + + // Properties. + ClassDB::bind_method(D_METHOD("get_custom_position"), &Example::get_custom_position); + ClassDB::bind_method(D_METHOD("set_custom_position", "position"), &Example::set_custom_position); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_position"), "set_custom_position", "get_custom_position"); + + // Signals. + ADD_SIGNAL(MethodInfo("custom_signal", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::INT, "value"))); + ClassDB::bind_method(D_METHOD("emit_custom_signal", "name", "value"), &Example::emit_custom_signal); + + // Constants. + BIND_ENUM_CONSTANT(FIRST); + BIND_ENUM_CONSTANT(ANSWER_TO_EVERYTHING); + + BIND_CONSTANT(CONSTANT_WITHOUT_ENUM); + + // Virtual function override. + BIND_VIRTUAL_METHOD(_has_point); +} + +// Methods. +void Example::simple_func() { + UtilityFunctions::print("Simple func called."); +} + +void Example::simple_const_func() const { + UtilityFunctions::print("Simple const func called."); +} + +String Example::return_something(const String &base) { + UtilityFunctions::print("Return something called."); + return base; +} + +Viewport *Example::return_something_const() const { + UtilityFunctions::print("Return something const called."); + if (is_inside_tree()) { + Viewport *result = get_viewport(); + return result; + } + return nullptr; +} + +Variant Example::varargs_func(const Variant **args, GDNativeInt arg_count, GDNativeCallError &error) { + UtilityFunctions::print("Varargs called with ", String::num(arg_count), " arguments"); + return arg_count; +} + +void Example::emit_custom_signal(const String &name, int value) { + emit_signal("custom_signal", name, value); +} + +// Properties. +void Example::set_custom_position(const Vector2 &pos) { + custom_position = pos; +} + +Vector2 Example::get_custom_position() const { + return custom_position; +} + +// Virtual function override. +bool Example::_has_point(const Vector2 &point) { + Label *label = get_node