Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/linux_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
- name: Minimal template (target=template_release, tests=yes, everything disabled)
cache-name: linux-template-minimal
target: template_release
sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no minizip=no module_spx_enabled=yes
sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no minizip=no module_spx_enabled=yes module_spine_godot_enabled=yes
bin: ./bin/godot.linuxbsd.template_release.x86_64
tests: true
artifact: true
Expand Down
1 change: 1 addition & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ opts.Add(BoolVariable("builtin_zlib", "Use the built-in zlib library", True))
opts.Add(BoolVariable("builtin_zstd", "Use the built-in Zstd library", True))

opts.Add(BoolVariable("spx", "Enable the spx library", True))
opts.Add(BoolVariable("spine_godot", "Enable the spine-godot library", True))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line adds a boolean variable to enable the spine-godot library. It's good to see this feature is configurable during the build process.


# Compilation environment setup
# CXX, CC, and LINK directly set the equivalent `env` values (which may still
Expand Down
63 changes: 63 additions & 0 deletions modules/spine_godot/GodotSpineExtension.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated April 5, 2025. Replaces all prior versions.
*
* Copyright (c) 2013-2025, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/

#include "GodotSpineExtension.h"
#ifdef SPINE_GODOT_EXTENSION
#include "SpineCommon.h"
#include <godot_cpp/core/memory.hpp>
#else
#include "core/os/memory.h"
#endif
#include <spine/SpineString.h>

spine::SpineExtension *spine::getDefaultExtension() {
return new GodotSpineExtension();
}

void *GodotSpineExtension::_alloc(size_t size, const char *file, int line) {
return memalloc(size);
}

void *GodotSpineExtension::_calloc(size_t size, const char *file, int line) {
auto p = memalloc(size);
memset(p, 0, size);
return p;
}

void *GodotSpineExtension::_realloc(void *ptr, size_t size, const char *file, int line) {
return memrealloc(ptr, size);
}

void GodotSpineExtension::_free(void *mem, const char *file, int line) {
memfree(mem);
}

char *GodotSpineExtension::_readFile(const spine::String &path, int *length) {
return NULL;
}
Comment on lines +61 to +63
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The _readFile function currently returns NULL. This means that the Spine runtime will not be able to load external files, such as shader programs, directly. This could limit the functionality of the module. Consider implementing file reading functionality to support loading external resources.

45 changes: 45 additions & 0 deletions modules/spine_godot/GodotSpineExtension.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated April 5, 2025. Replaces all prior versions.
*
* Copyright (c) 2013-2025, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/

#pragma once

#include <spine/Extension.h>

class GodotSpineExtension : public spine::SpineExtension {
protected:
virtual void *_alloc(size_t size, const char *file, int line);

virtual void *_calloc(size_t size, const char *file, int line);

virtual void *_realloc(void *ptr, size_t size, const char *file, int line);

virtual void _free(void *mem, const char *file, int line);

virtual char *_readFile(const spine::String &path, int *length);
};
16 changes: 16 additions & 0 deletions modules/spine_godot/SCsub
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Import('env')
Import("env_modules")

# Need to add the include path to env so the vsproj generator consumes it.
if env["vsproj"]:
env.Append(CPPPATH=["#modules/spine_godot/spine-cpp/include"])

env_spine_runtime = env.Clone()
env_spine_runtime.Append(CPPPATH=["#modules/spine_godot/spine-cpp/include"])
env_spine_runtime.add_source_files(env.modules_sources, "spine-cpp/src/spine/*.cpp")
env_spine_runtime.add_source_files(env.modules_sources, "*.cpp")

# Needed on Clang to not have a gazillion -Winconsistent-missing-override warnings for GDCLASS
# I do not understand why other modules using GDCLASS do not have this issue when compiling.
if not env_spine_runtime.msvc:
env_spine_runtime.Append(CXXFLAGS=["-Wno-inconsistent-missing-override"])
109 changes: 109 additions & 0 deletions modules/spine_godot/SpineAnimation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated April 5, 2025. Replaces all prior versions.
*
* Copyright (c) 2013-2025, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/

#include "SpineAnimation.h"
#include "SpineSkeleton.h"
#include "SpineEvent.h"
#include "SpineTimeline.h"
#if VERSION_MAJOR == 3
#include "core/method_bind_ext.gen.inc"
#endif

void SpineAnimation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_name"), &SpineAnimation::get_name);
ClassDB::bind_method(D_METHOD("get_duration"), &SpineAnimation::get_duration);
ClassDB::bind_method(D_METHOD("set_duration", "duration"), &SpineAnimation::set_duration);

ClassDB::bind_method(D_METHOD("apply", "skeleton", "last_time", "time", "loop", "events", "alpha", "blend", "direction"), &SpineAnimation::apply);
ClassDB::bind_method(D_METHOD("get_timelines"), &SpineAnimation::get_timelines);
ClassDB::bind_method(D_METHOD("has_timeline", "ids"), &SpineAnimation::has_timeline);
}

String SpineAnimation::get_name() {
SPINE_CHECK(get_spine_object(), "")
String name;
#if (VERSION_MAJOR >= 4 && VERSION_MINOR >= 5)
name = String::utf8(get_spine_object()->getName().buffer());
#else
name.parse_utf8(get_spine_object()->getName().buffer());
#endif
return name;
}

float SpineAnimation::get_duration() {
SPINE_CHECK(get_spine_object(), 0)
return get_spine_object()->getDuration();
}

void SpineAnimation::set_duration(float duration) {
SPINE_CHECK(get_spine_object(), )
get_spine_object()->setDuration(duration);
}

void SpineAnimation::apply(Ref<SpineSkeleton> skeleton, float last_time, float time, bool loop,
Array events, float alpha, SpineConstant::MixBlend blend,
SpineConstant::MixDirection direction) {
SPINE_CHECK(get_spine_object(), )
spine::Vector<spine::Event *> spineEvents;
get_spine_object()->apply(*(skeleton->get_spine_object()), last_time, time, loop, &spineEvents, alpha, (spine::MixBlend) blend, (spine::MixDirection) direction);
for (int i = 0; i < (int) spineEvents.size(); ++i) {
auto event_ref = memnew(SpineEvent);
event_ref->set_spine_object(skeleton->get_spine_owner(), spineEvents[i]);
events.append(event_ref);
}
Comment on lines +75 to +79
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The event_ref is allocated using memnew but is then appended to the events array. The ownership of this event_ref is transferred to the events array. The event_ref should not be manually deallocated, as the Godot engine will handle the memory management of the array elements. Consider removing the manual deallocation to prevent potential double frees.

}

Array SpineAnimation::get_timelines() {
Array result;
SPINE_CHECK(get_spine_object(), result)
auto &timelines = get_spine_object()->getTimelines();
result.resize((int) timelines.size());

for (int i = 0; i < (int) result.size(); ++i) {
auto timeline_ref = Ref<SpineTimeline>(memnew(SpineTimeline));
timeline_ref->set_spine_object(get_spine_owner(), timelines[i]);
#ifdef SPINE_GODOT_EXTENSION
result[i] = timeline_ref;
#else
result.set(i, timeline_ref);
#endif
}
return result;
}

bool SpineAnimation::has_timeline(Array ids) {
SPINE_CHECK(get_spine_object(), false)
spine::Vector<spine::PropertyId> property_ids;
property_ids.setSize(ids.size(), 0);

for (int i = 0; i < (int) property_ids.size(); ++i) {
property_ids[i] = (int64_t) ids[i];
}
return get_spine_object()->hasTimeline(property_ids);
}
59 changes: 59 additions & 0 deletions modules/spine_godot/SpineAnimation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated April 5, 2025. Replaces all prior versions.
*
* Copyright (c) 2013-2025, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/

#pragma once

#include "SpineCommon.h"
#include "SpineConstant.h"
#include <spine/Animation.h>

class SpineEvent;
class SpineSkeleton;
class SpineTimeline;
class SpineSkeletonDataResource;

class SpineAnimation : public SpineSkeletonDataResourceOwnedObject<spine::Animation> {
GDCLASS(SpineAnimation, SpineObjectWrapper)

protected:
static void _bind_methods();

public:
void apply(Ref<SpineSkeleton> skeleton, float last_time, float time, bool loop, Array events, float alpha, SpineConstant::MixBlend blend, SpineConstant::MixDirection direction);

Array get_timelines();

bool has_timeline(Array ids);

String get_name();

float get_duration();

void set_duration(float duration);
};
Loading
Loading