GDExtension support, heavy WIP

This commit is contained in:
Mario Zechner 2024-07-05 19:05:42 +02:00
parent f80ac86bbf
commit 1101e71ec3
17 changed files with 189 additions and 6 deletions

1
.gitignore vendored
View File

@ -204,3 +204,4 @@ spine-flutter/src/spine-cpp-lite
spine-sdl/.vs
spine-ts/spine-canvaskit/dist
spine-ts/output.png
spine-godot/godot-cpp

View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.14)
project(spine_godot_extension)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
file(GLOB INCLUDES "spine_godot/**/*.h")
file(GLOB SOURCES "spine_godot/*.cpp")
string(REPLACE ";" "\n" SOURCES_LIST "${SOURCES}")
message(STATUS "Source files:\n${SOURCES_LIST}")
include_directories(
spine_godot
spine_godot/spine-cpp/include
godot-cpp/gdextension
godot-cpp/include
godot-cpp/gen/include
)
add_library(spine_godot_extension SHARED ${SOURCES})
target_compile_definitions(spine_godot_extension PRIVATE SPINE_GODOT_EXTENSION)
# Link Godot's GDExtension API
target_link_libraries(spine_godot_extension PRIVATE godot-cpp)

View File

@ -18,10 +18,13 @@ if [ $# -lt 2 ] || [ $# -gt 4 ]; then
fi
branch=${1%/}
godot_version=$(echo "$branch" | grep -o '^[0-9]*\.[0-9]*')
dev=${2%/}
mono=false
repo=https://github.com/godotengine/godot.git
echo "Godot version: $godot_version"
if [[ $# -eq 3 && "$branch" != 3* ]]; then
mono=${3%/}
fi
@ -41,6 +44,16 @@ if [ $# -eq 4 ]; then
fi
pushd ..
echo "--- Cloning GDExtensions"
rm -rf godot-cpp
git clone https://github.com/godotengine/godot-cpp
pushd godot-cpp
git submodule update --init
git checkout $godot_version
popd
echo "--- Cloning Godot"
rm -rf godot
git clone --depth 1 $repo -b $branch
if [ $dev = "true" ]; then

View File

@ -28,6 +28,11 @@
*****************************************************************************/
#include "GodotSpineExtension.h"
#ifdef SPINE_GODOT_EXTENSION
#include "SpineCommon.h"
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/classes/file_access.hpp>
#else
#include "core/os/memory.h"
#include "core/version.h"
#if VERSION_MAJOR > 3
@ -35,6 +40,7 @@
#else
#include "core/os/file_access.h"
#endif
#endif
#include <spine/SpineString.h>
spine::SpineExtension *spine::getDefaultExtension() {
@ -61,6 +67,10 @@ void GodotSpineExtension::_free(void *mem, const char *file, int line) {
char *GodotSpineExtension::_readFile(const spine::String &path, int *length) {
Error error;
#ifdef SPINE_GODOT_EXTENSION
// FIXME no error parameter!
auto res = FileAccess::get_file_as_bytes(String(path.buffer()));
#else
#if VERSION_MAJOR > 3
auto res = FileAccess::get_file_as_bytes(String(path.buffer()), &error);
#else
@ -70,6 +80,7 @@ char *GodotSpineExtension::_readFile(const spine::String &path, int *length) {
if (length) *length = 0;
return NULL;
}
#endif
auto r = alloc<char>(res.size(), __FILE__, __LINE__);
memcpy(r, res.ptr(), res.size());
if (length) *length = res.size();

View File

@ -30,8 +30,13 @@
#pragma once
#include "SpineSprite.h"
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/classes/animation_player.hpp>
#include <godot_cpp/classes/animation.hpp>
#else
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#endif
class SpineAnimationTrack : public Node {
GDCLASS(SpineAnimationTrack, Node)

View File

@ -29,8 +29,15 @@
#include "SpineAtlasResource.h"
#include "SpineRendererObject.h"
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/classes/json.hpp>
#include <godot_cpp/classes/texture.hpp>
#include <godot_cpp/classes/file_access.hpp>
#else
#include "core/io/json.h"
#include "scene/resources/texture.h"
#endif
#include <spine/TextureLoader.h>
class GodotSpineTextureLoader : public spine::TextureLoader {
@ -44,16 +51,16 @@ public:
}
static String fix_path(const String &path) {
if (path.size() > 5 && path[4] == '/' && path[5] == '/') return path;
if (SSIZE(path) > 5 && path[4] == '/' && path[5] == '/') return path;
const String prefix = "res:/";
auto i = path.find(prefix);
auto sub_str_pos = i + prefix.size() - 1;
auto sub_str_pos = i + SSIZE(prefix) - 1;
if (sub_str_pos < 0) return path;
auto res = path.substr(sub_str_pos);
if (!EMPTY(res)) {
if (res[0] != '/') {
return prefix + "/" + res;
return prefix + String("/") + res;
} else {
return prefix + res;
}
@ -65,10 +72,15 @@ public:
Error error = OK;
auto fixed_path = fix_path(String(path.buffer()));
#if SPINE_GODOT_EXTENSION
// FIXME no error parameter
Ref<Texture2D> texture = ResourceLoader::get_singleton()->load(fixed_path, "", ResourceLoader::CACHE_MODE_REUSE);
#else
#if VERSION_MAJOR > 3
Ref<Texture2D> texture = ResourceLoader::load(fixed_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &error);
#else
Ref<Texture> texture = ResourceLoader::load(fixed_path, "", false, &error);
#endif
#endif
if (error != OK || !texture.is_valid()) {
ERR_PRINT(vformat("Can't load texture: \"%s\"", String(path.buffer())));
@ -85,11 +97,19 @@ public:
renderer_object->normal_map = Ref<Texture>(nullptr);
String new_path = vformat("%s/%s_%s", fixed_path.get_base_dir(), normal_map_prefix, fixed_path.get_file());
#if SPINE_GODOT_EXTENSION
if (ResourceLoader::get_singleton()->exists(new_path)) {
Ref<Texture> normal_map = ResourceLoader::get_singleton()->load(new_path);
normal_maps->append(normal_map);
renderer_object->normal_map = normal_map;
}
#else
if (ResourceLoader::exists(new_path)) {
Ref<Texture> normal_map = ResourceLoader::load(new_path);
normal_maps->append(normal_map);
renderer_object->normal_map = normal_map;
}
#endif
#if VERSION_MAJOR > 3
renderer_object->canvas_texture.instantiate();

View File

@ -30,10 +30,19 @@
#pragma once
#include "SpineCommon.h"
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/classes/resource_loader.hpp>
#include <godot_cpp/classes/resource_format_loader.hpp>
#include <godot_cpp/classes/resource_saver.hpp>
#include <godot_cpp/classes/resource_format_saver.hpp>
#include <spine/Atlas.h>
#else
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/io/image_loader.h"
#include <spine/Atlas.h>
#endif
class GodotSpineTextureLoader;
@ -89,6 +98,15 @@ class SpineAtlasResourceFormatLoader : public ResourceFormatLoader {
GDCLASS(SpineAtlasResourceFormatLoader, ResourceFormatLoader)
public:
#ifdef SPINE_GODOT_EXTENSION
PackedStringArray _get_recognized_extensions();
bool _handles_type(const StringName &type);
String _get_resource_type(const String &path);
Variant _load(const String &path, const String &original_path, bool use_sub_threads, int32_t cache_mode);
#else
#if VERSION_MAJOR > 3
RES load(const String &path, const String &original_path, Error *error, bool use_sub_threads, float *progress, CacheMode cache_mode) override;
#else
@ -100,12 +118,18 @@ public:
bool handles_type(const String &type) const override;
String get_resource_type(const String &path) const override;
#endif
};
class SpineAtlasResourceFormatSaver : public ResourceFormatSaver {
GDCLASS(SpineAtlasResourceFormatSaver, ResourceFormatSaver)
public:
#ifdef SPINE_GODOT_EXTENSION
Error _save(const Ref<Resource> &resource, const String &path, uint32_t flags) override;
bool _recognize(const Ref<Resource> &resource);
PackedStringArray _get_recognized_extensions(const Ref<Resource> &resource);
#else
#if VERSION_MAJOR > 3
Error save(const RES &resource, const String &path, uint32_t flags) override;
#else
@ -115,4 +139,5 @@ public:
void get_recognized_extensions(const RES &resource, List<String> *extensions) const override;
bool recognize(const RES &resource) const override;
#endif
};

View File

@ -48,7 +48,7 @@ public:
Ref<SpineAttachment> copy();
void set_spine_object(const SpineSkeletonDataResource *_owner, spine::Attachment *_object) {
void set_spine_object(const SpineSkeletonDataResource *_owner, spine::Attachment *_object) override {
if (get_spine_object()) get_spine_object()->dereference();
_set_spine_object_internal(_owner, _object);
if (_object) _object->reference();

View File

@ -32,7 +32,11 @@
#include "SpineCommon.h"
#include "SpineBoneData.h"
#include "SpineConstant.h"
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/classes/node2d.hpp>
#else
#include "scene/2d/node_2d.h"
#endif
#include <spine/Bone.h>
class SpineSkeleton;

View File

@ -30,6 +30,28 @@
#ifndef SPINE_COMMON_H
#define SPINE_COMMON_H
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/core/version.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/variant/string_name.hpp>
using namespace godot;
#define REFCOUNTED RefCounted
#define EMPTY(x) ((x).is_empty())
#define EMPTY_PTR(x) ((x)->is_empty())
#define SSIZE(x) ((x).length())
#define INSTANTIATE(x) (x).instantiate()
#define NOTIFY_PROPERTY_LIST_CHANGED() notify_property_list_changed()
#define VARIANT_FLOAT Variant::FLOAT
#define PROPERTY_USAGE_NOEDITOR PROPERTY_USAGE_NO_EDITOR
#define RES Ref<Resource>
#define REF Ref<RefCounted>
#define GEOMETRY2D Geometry2D
#define VERSION_MAJOR GODOT_VERSION_MAJOR
#define VERSION_MINOR GODOT_VERSION_MINOR
// FIXME this doesn't do the same as the engine SNAME in terms of caching
#define SNAME(name) StringName(name)
#define RS RenderingServer
#else
#include "core/version.h"
#if VERSION_MAJOR > 3
#include "core/core_bind.h"
@ -37,6 +59,7 @@
#define REFCOUNTED RefCounted
#define EMPTY(x) ((x).is_empty())
#define EMPTY_PTR(x) ((x)->is_empty())
#define SSIZE(x) ((x).size())
#define INSTANTIATE(x) (x).instantiate()
#define NOTIFY_PROPERTY_LIST_CHANGED() notify_property_list_changed()
#define VARIANT_FLOAT Variant::FLOAT
@ -51,6 +74,7 @@
#define REFCOUNTED Reference
#define EMPTY(x) ((x).empty())
#define EMPTY_PTR(x) ((x)->empty())
#define SSIZE(x) ((x).size())
#define INSTANTIATE(x) (x).instance()
#define NOTIFY_PROPERTY_LIST_CHANGED() property_list_changed_notify()
#define VARIANT_FLOAT Variant::REAL
@ -60,6 +84,7 @@
#define SNAME(m_arg) ([]() -> const StringName & { static StringName sname = _scs_create(m_arg); return sname; })()
#endif
#endif
#endif
#define SPINE_CHECK(obj, ret) \
if (!(obj)) { \

View File

@ -30,11 +30,18 @@
#ifndef GODOT_SPINERENDEREROBJECT_H
#define GODOT_SPINERENDEREROBJECT_H
#include "SpineCommon.h"
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/classes/texture.hpp>
#include <godot_cpp/classes/canvas_texture.hpp>
#else
#include <scene/resources/texture.h>
#if VERSION_MAJOR > 3
#include <scene/main/canvas_item.h>
#endif
#endif
struct SpineRendererObject {
Ref<Texture> texture;

View File

@ -29,7 +29,6 @@
#include "SpineSkeletonDataResource.h"
#include "SpineCommon.h"
#include "core/io/marshalls.h"
void SpineAnimationMix::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_from", "from"),

View File

@ -28,6 +28,10 @@
*****************************************************************************/
#include "SpineSkeletonFileResource.h"
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/classes/file_access.hpp>
#else
#if VERSION_MAJOR > 3
#include "core/error/error_list.h"
#include "core/error/error_macros.h"
@ -37,6 +41,7 @@
#include "core/error_macros.h"
#include "core/os/file_access.h"
#endif
#endif
#include <spine/Json.h>
#include <spine/Version.h>
#include <spine/Extension.h>

View File

@ -30,8 +30,18 @@
#pragma once
#include "SpineCommon.h"
#ifdef SPINE_GODOT_EXTENSION
#include <godot_cpp/classes/resource_loader.hpp>
#include <godot_cpp/classes/resource_format_loader.hpp>
#include <godot_cpp/classes/resource_saver.hpp>
#include <godot_cpp/classes/resource_format_saver.hpp>
#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/templates/vector.hpp>
#else
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#endif
#include <spine/Vector.h>
class SpineSkeletonFileResource : public Resource {
GDCLASS(SpineSkeletonFileResource, Resource);
@ -62,6 +72,15 @@ class SpineSkeletonFileResourceFormatLoader : public ResourceFormatLoader {
GDCLASS(SpineSkeletonFileResourceFormatLoader, ResourceFormatLoader);
public:
#ifdef SPINE_GODOT_EXTENSION
PackedStringArray _get_recognized_extensions();
bool _handles_type(const StringName &type);
String _get_resource_type(const String &path);
Variant _load(const String &path, const String &original_path, bool use_sub_threads, int32_t cache_mode);
#else
#if VERSION_MAJOR > 3
RES load(const String &path, const String &original_path, Error *error, bool use_sub_threads, float *progress, CacheMode cache_mode);
#else
@ -73,12 +92,18 @@ public:
bool handles_type(const String &type) const override;
String get_resource_type(const String &path) const override;
#endif
};
class SpineSkeletonFileResourceFormatSaver : public ResourceFormatSaver {
GDCLASS(SpineSkeletonFileResourceFormatSaver, ResourceFormatSaver);
public:
#ifdef SPINE_GODOT_EXTENSION
Error _save(const Ref<Resource> &resource, const String &path, uint32_t flags) override;
bool _recognize(const Ref<Resource> &resource);
PackedStringArray _get_recognized_extensions(const Ref<Resource> &resource);
#else
#if VERSION_MAJOR > 3
Error save(const RES &resource, const String &path, uint32_t flags) override;
#else
@ -88,4 +113,5 @@ public:
void get_recognized_extensions(const RES &resource, List<String> *p_extensions) const override;
bool recognize(const RES &p_resource) const override;
#endif
};

View File

@ -31,7 +31,15 @@
#include "SpineSkeleton.h"
#include "SpineAnimationState.h"
#ifdef SPINE_GODOT_EXTENSION
#include "SpineCommon.h"
#include <godot_cpp/classes/node2d.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/classes/rendering_server.hpp>
#include <godot_cpp/classes/canvas_item_material.hpp>
#else
#include "scene/2d/node_2d.h"
#endif
class SpineSlotNode;
@ -84,7 +92,11 @@ public:
SpineMesh2D() : renderer_object(nullptr), indices_changed(true), num_vertices(0), num_indices(0), vertex_stride(0), normal_tangent_stride(0), attribute_stride(0){};
~SpineMesh2D() {
if (mesh.is_valid()) {
#ifdef SPINE_GODOT_EXTENSION
RS::get_singleton()->free_rid(mesh);
#else
RS::get_singleton()->free(mesh);
#endif
}
}
#else
@ -160,7 +172,7 @@ protected:
void draw();
void draw_bone(spine::Bone *bone, const Color &color);
void callback(spine::AnimationState *state, spine::EventType type, spine::TrackEntry *entry, spine::Event *event);
void callback(spine::AnimationState *state, spine::EventType type, spine::TrackEntry *entry, spine::Event *event) override;
public:
SpineSprite();

View File

@ -28,7 +28,10 @@
*****************************************************************************/
#include "SpineCommon.h"
#ifdef SPINE_GODOT_EXTENSION
#else
#include "modules/register_module_types.h"
#endif
#include "register_types.h"
#include "SpineAtlasResource.h"
#include "SpineSkeletonFileResource.h"

View File

@ -32,7 +32,9 @@
#include "SpineCommon.h"
#if VERSION_MAJOR > 3
#ifndef SPINE_GODOT_EXTENSION
#include "modules/register_module_types.h"
#endif
void initialize_spine_godot_module(ModuleInitializationLevel level);
void uninitialize_spine_godot_module(ModuleInitializationLevel level);
#else