Skip to content

Commit 6c9a41d

Browse files
kisgkonczg
andcommitted
LibGodot Feature
* Based on top of the GDExtensionLoader PR: godotengine#91166 * Add a new GodotInstance GDCLASS that provides startup and iteration commands to control a Godot instance. * Adds a libgodot_create_godot_instance entry point that creates a new Godot instance and returns a GodotInstance object. * Adds a libgodot_destroy_godot_instance entry point that destroys the Godot instance. * Allow specifying an external native rendering surface handle to render Godot into the UI of a host application. * It is also possible to embed multiple Godot windows into the UI of a host application. * Currently supported on MacOS and iOS Sample Apps: https://github.com/migeran/libgodot_project Developed by [Migeran](https://migeran.com) Sponsors & Acknowledgements: * Initial development sponsored by [Smirk Software](https://www.smirk.gg/) * Rebasing to Godot 4.3 and further development sponsored by [Xibbon Inc.](https://xibbon.com) * The GDExtension registration of the host process & build system changes were based on @Faolan-Rad's LibGodot PR: godotengine#72883 Co-Authored-By: Gabor Koncz <gabor.koncz@migeran.com>
1 parent 92e51fc commit 6c9a41d

File tree

92 files changed

+2860
-462
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+2860
-462
lines changed

SConstruct

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ env.__class__.use_windows_spawn_fix = methods.use_windows_spawn_fix
163163

164164
env.__class__.add_shared_library = methods.add_shared_library
165165
env.__class__.add_library = methods.add_library
166-
env.__class__.add_program = methods.add_program
167166
env.__class__.CommandNoCache = methods.CommandNoCache
168167
env.__class__.Run = methods.Run
169168
env.__class__.disable_warnings = methods.disable_warnings
@@ -231,6 +230,14 @@ opts.Add("custom_modules", "A list of comma-separated directory paths containing
231230
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
232231

233232
# Advanced options
233+
opts.Add(
234+
EnumVariable(
235+
"library_type",
236+
"Build library type",
237+
"executable",
238+
("executable", "static_library", "shared_library"),
239+
)
240+
)
234241
opts.Add(
235242
BoolVariable(
236243
"dev_mode", "Alias for dev options: verbose=yes warnings=extra werror=yes tests=yes strict_checks=yes", False
@@ -333,7 +340,18 @@ if env["import_env_vars"]:
333340
if env.scons_version < (4, 3) and not env["platform"]:
334341
env["platform"] = env["p"]
335342

336-
if env["platform"] == "":
343+
if env["library_type"] == "static_library":
344+
env.Append(CPPDEFINES=["LIBGODOT_ENABLED"])
345+
elif env["library_type"] == "shared_library":
346+
env.Append(CPPDEFINES=["LIBGODOT_ENABLED"])
347+
env.Append(CCFLAGS=["-fPIC"])
348+
env.Append(STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME=True)
349+
else:
350+
env.__class__.add_program = methods.add_program
351+
352+
if env["platform"] != "":
353+
selected_platform = env["platform"]
354+
else:
337355
# Missing `platform` argument, try to detect platform automatically
338356
if (
339357
sys.platform.startswith("linux")

core/config/project_settings.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ const PackedStringArray ProjectSettings::get_required_features() {
8888
// Returns the features supported by this build of Godot. Includes all required features.
8989
const PackedStringArray ProjectSettings::_get_supported_features() {
9090
PackedStringArray features = get_required_features();
91+
92+
#ifdef LIBGODOT_ENABLED
93+
features.append("LibGodot");
94+
#endif
95+
9196
#ifdef MODULE_MONO_ENABLED
9297
features.append("C#");
9398
#endif
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**************************************************************************/
2+
/* gdextension_function_loader.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#include "gdextension_function_loader.h"
32+
#include "core/config/project_settings.h"
33+
#include "gdextension.h"
34+
35+
Error GDExtensionFunctionLoader::open_library(const String &p_path) {
36+
ERR_FAIL_COND_V_MSG(!p_path.begins_with("libgodot://"), ERR_FILE_NOT_FOUND, "Function based GDExtensions should have a path starting with libgodot://");
37+
ERR_FAIL_COND_V_MSG(!initialization_function, ERR_DOES_NOT_EXIST, "Initialization function is required for function based GDExtensions.");
38+
39+
library_path = p_path;
40+
41+
return OK;
42+
}
43+
44+
Error GDExtensionFunctionLoader::initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) {
45+
ERR_FAIL_COND_V_MSG(!initialization_function, ERR_DOES_NOT_EXIST, "Initialization function is required for function based GDExtensions.");
46+
GDExtensionBool ret = initialization_function(p_get_proc_address, p_extension.ptr(), r_initialization);
47+
48+
if (ret) {
49+
return OK;
50+
} else {
51+
ERR_PRINT("GDExtension initialization function for '" + library_path + "' returned an error.");
52+
return FAILED;
53+
}
54+
}
55+
56+
void GDExtensionFunctionLoader::close_library() {
57+
initialization_function = nullptr;
58+
library_path.clear();
59+
}
60+
61+
bool GDExtensionFunctionLoader::is_library_open() const {
62+
return !library_path.is_empty();
63+
}
64+
65+
bool GDExtensionFunctionLoader::has_library_changed() const {
66+
return false;
67+
}
68+
69+
bool GDExtensionFunctionLoader::library_exists() const {
70+
return true;
71+
}
72+
73+
void GDExtensionFunctionLoader::set_initialization_function(GDExtensionInitializationFunction p_initialization_function) {
74+
initialization_function = p_initialization_function;
75+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**************************************************************************/
2+
/* gdextension_function_loader.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#ifndef GDEXTENSION_FUNCTION_LOADER_H
32+
#define GDEXTENSION_FUNCTION_LOADER_H
33+
34+
#include "core/extension/gdextension_loader.h"
35+
#include "core/os/shared_object.h"
36+
#include <functional>
37+
38+
class GDExtension;
39+
40+
class GDExtensionFunctionLoader : public GDExtensionLoader {
41+
friend class GDExtensionManager;
42+
friend class GDExtension;
43+
44+
private:
45+
String library_path;
46+
GDExtensionInitializationFunction initialization_function = nullptr;
47+
48+
public:
49+
Error open_library(const String &p_path) override;
50+
Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref<GDExtension> &p_extension, GDExtensionInitialization *r_initialization) override;
51+
void close_library() override;
52+
bool is_library_open() const override;
53+
bool has_library_changed() const override;
54+
bool library_exists() const override;
55+
56+
void set_initialization_function(GDExtensionInitializationFunction initialization_function);
57+
};
58+
59+
#endif // GDEXTENSION_FUNCTION_LOADER_H

core/extension/gdextension_manager.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "gdextension_manager.h"
3232

3333
#include "core/extension/gdextension_compat_hashes.h"
34+
#include "core/extension/gdextension_function_loader.h"
3435
#include "core/extension/gdextension_library_loader.h"
3536
#include "core/io/dir_access.h"
3637
#include "core/io/file_access.h"
@@ -86,7 +87,14 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
8687
GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
8788
Ref<GDExtensionLibraryLoader> loader;
8889
loader.instantiate();
89-
return GDExtensionManager::get_singleton()->load_extension_with_loader(p_path, loader);
90+
return load_extension_with_loader(p_path, loader);
91+
}
92+
93+
GDExtensionManager::LoadStatus GDExtensionManager::load_function_extension(const String &p_path, GDExtensionConstPtr<const GDExtensionInitializationFunction> p_init_func) {
94+
Ref<GDExtensionFunctionLoader> func_loader;
95+
func_loader.instantiate();
96+
func_loader->set_initialization_function((GDExtensionInitializationFunction) * (p_init_func.data));
97+
return load_extension_with_loader(p_path, func_loader);
9098
}
9199

92100
GDExtensionManager::LoadStatus GDExtensionManager::load_extension_with_loader(const String &p_path, const Ref<GDExtensionLoader> &p_loader) {
@@ -360,6 +368,7 @@ GDExtensionManager *GDExtensionManager::get_singleton() {
360368

361369
void GDExtensionManager::_bind_methods() {
362370
ClassDB::bind_method(D_METHOD("load_extension", "path"), &GDExtensionManager::load_extension);
371+
ClassDB::bind_method(D_METHOD("load_function_extension", "path", "init_func"), &GDExtensionManager::load_function_extension);
363372
ClassDB::bind_method(D_METHOD("reload_extension", "path"), &GDExtensionManager::reload_extension);
364373
ClassDB::bind_method(D_METHOD("unload_extension", "path"), &GDExtensionManager::unload_extension);
365374
ClassDB::bind_method(D_METHOD("is_extension_loaded", "path"), &GDExtensionManager::is_extension_loaded);

core/extension/gdextension_manager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
#define GDEXTENSION_MANAGER_H
3333

3434
#include "core/extension/gdextension.h"
35+
#include "core/variant/native_ptr.h"
36+
37+
GDVIRTUAL_NATIVE_PTR(GDExtensionInitializationFunction)
3538

3639
class GDExtensionManager : public Object {
3740
GDCLASS(GDExtensionManager, Object);
@@ -63,6 +66,7 @@ class GDExtensionManager : public Object {
6366

6467
public:
6568
LoadStatus load_extension(const String &p_path);
69+
LoadStatus load_function_extension(const String &p_path, GDExtensionConstPtr<const GDExtensionInitializationFunction> p_init_func);
6670
LoadStatus load_extension_with_loader(const String &p_path, const Ref<GDExtensionLoader> &p_loader);
6771
LoadStatus reload_extension(const String &p_path);
6872
LoadStatus unload_extension(const String &p_path);

core/extension/godot_instance.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**************************************************************************/
2+
/* godot_instance.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#include "godot_instance.h"
32+
#include "core/extension/gdextension_manager.h"
33+
#include "main/main.h"
34+
#include "servers/display_server.h"
35+
36+
void GodotInstance::_bind_methods() {
37+
ClassDB::bind_method(D_METHOD("start"), &GodotInstance::start);
38+
ClassDB::bind_method(D_METHOD("is_started"), &GodotInstance::is_started);
39+
ClassDB::bind_method(D_METHOD("iteration"), &GodotInstance::iteration);
40+
}
41+
42+
GodotInstance::GodotInstance() {
43+
}
44+
45+
GodotInstance::~GodotInstance() {
46+
}
47+
48+
bool GodotInstance::initialize(GDExtensionInitializationFunction p_init_func) {
49+
GDExtensionManager *gdextension_manager = GDExtensionManager::get_singleton();
50+
GDExtensionConstPtr<const GDExtensionInitializationFunction> ptr((const GDExtensionInitializationFunction *)&p_init_func);
51+
GDExtensionManager::LoadStatus status = gdextension_manager->load_function_extension("libgodot://main", ptr);
52+
return status == GDExtensionManager::LoadStatus::LOAD_STATUS_OK;
53+
}
54+
55+
bool GodotInstance::start() {
56+
Error err = Main::setup2();
57+
if (err != OK) {
58+
return false;
59+
}
60+
started = Main::start() == EXIT_SUCCESS;
61+
if (started) {
62+
OS::get_singleton()->get_main_loop()->initialize();
63+
}
64+
return started;
65+
}
66+
67+
bool GodotInstance::is_started() {
68+
return started;
69+
}
70+
71+
bool GodotInstance::iteration() {
72+
DisplayServer::get_singleton()->process_events();
73+
return Main::iteration();
74+
}
75+
76+
void GodotInstance::stop() {
77+
if (started) {
78+
OS::get_singleton()->get_main_loop()->finalize();
79+
}
80+
started = false;
81+
}

platform/macos/rendering_context_driver_vulkan_macos.h renamed to core/extension/godot_instance.h

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**************************************************************************/
2-
/* rendering_context_driver_vulkan_macos.h */
2+
/* godot_instance.h */
33
/**************************************************************************/
44
/* This file is part of: */
55
/* GODOT ENGINE */
@@ -28,31 +28,30 @@
2828
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
2929
/**************************************************************************/
3030

31-
#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_MACOS_H
32-
#define RENDERING_CONTEXT_DRIVER_VULKAN_MACOS_H
31+
#ifndef GODOT_INSTANCE_H
32+
#define GODOT_INSTANCE_H
3333

34-
#ifdef VULKAN_ENABLED
34+
#include "core/extension/gdextension_interface.h"
35+
#include "core/object/class_db.h"
36+
#include "core/object/object.h"
3537

36-
#include "drivers/vulkan/rendering_context_driver_vulkan.h"
38+
class GodotInstance : public Object {
39+
GDCLASS(GodotInstance, Object);
3740

38-
#import <QuartzCore/CAMetalLayer.h>
41+
static void _bind_methods();
3942

40-
class RenderingContextDriverVulkanMacOS : public RenderingContextDriverVulkan {
41-
private:
42-
virtual const char *_get_platform_surface_extension() const override final;
43-
44-
protected:
45-
SurfaceID surface_create(const void *p_platform_data) override final;
43+
bool started = false;
4644

4745
public:
48-
struct WindowPlatformData {
49-
CAMetalLayer *const *layer_ptr;
50-
};
46+
GodotInstance();
47+
~GodotInstance();
5148

52-
RenderingContextDriverVulkanMacOS();
53-
~RenderingContextDriverVulkanMacOS();
54-
};
49+
bool initialize(GDExtensionInitializationFunction p_init_func);
5550

56-
#endif // VULKAN_ENABLED
51+
bool start();
52+
bool is_started();
53+
bool iteration();
54+
void stop();
55+
};
5756

58-
#endif // RENDERING_CONTEXT_DRIVER_VULKAN_MACOS_H
57+
#endif // GODOT_INSTANCE_H

0 commit comments

Comments
 (0)