Revert "[ue] Sync spine-cpp copy for AnimationState additive/hold rework, Skin placeholder rename"

This reverts commit 60205bf2618b1c17a14cd2cb0420208fb28cc9c2.
This commit is contained in:
Mario Zechner 2026-03-24 21:31:48 +01:00
parent 60205bf261
commit a64c5e0a27
86 changed files with 0 additions and 16026 deletions

View File

@ -1,136 +0,0 @@
/******************************************************************************
* 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 <spine/Animation.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Timeline.h>
#include <spine/BoneTimeline.h>
#include <spine/RotateTimeline.h>
#include <spine/TranslateTimeline.h>
#include <spine/ArrayUtils.h>
#include <stdint.h>
using namespace spine;
Animation::Animation(const String &name, Array<Timeline *> &timelines, float duration)
: _timelines(), _timelineIds(), _bones(), _duration(duration), _name(name) {
setTimelines(timelines);
}
bool Animation::hasTimeline(Array<PropertyId> &ids) {
for (size_t i = 0; i < ids.size(); i++) {
if (_timelineIds.containsKey(ids[i])) return true;
}
return false;
}
Animation::~Animation() {
ArrayUtils::deleteElements(_timelines);
}
void Animation::apply(Skeleton &skeleton, float lastTime, float time, bool loop, Array<Event *> *events, float alpha, bool fromSetup, bool add,
bool out, bool appliedPose) {
if (loop && _duration != 0) {
time = MathUtil::fmod(time, _duration);
if (lastTime > 0) {
lastTime = MathUtil::fmod(lastTime, _duration);
}
}
for (size_t i = 0, n = _timelines.size(); i < n; ++i) {
_timelines[i]->apply(skeleton, lastTime, time, events, alpha, fromSetup, add, out, appliedPose);
}
}
const String &Animation::getName() {
return _name;
}
const Array<int> &Animation::getBones() {
return _bones;
}
Array<Timeline *> &Animation::getTimelines() {
return _timelines;
}
float Animation::getDuration() {
return _duration;
}
void Animation::setDuration(float inValue) {
_duration = inValue;
}
int Animation::search(Array<float> &frames, float target) {
size_t n = (int) frames.size();
for (size_t i = 1; i < n; i++) {
if (frames[i] > target) return (int) (i - 1);
}
return (int) (n - 1);
}
int Animation::search(Array<float> &frames, float target, int step) {
size_t n = frames.size();
for (size_t i = step; i < n; i += step)
if (frames[i] > target) return (int) (i - step);
return (int) (n - step);
}
void Animation::setTimelines(Array<Timeline *> &timelines) {
_timelines = timelines;
size_t n = timelines.size();
_timelineIds.clear();
_bones.clear();
HashMap<int, bool> boneSet;
for (size_t i = 0; i < n; i++) {
Timeline *timeline = timelines[i];
Array<PropertyId> &propertyIds = timeline->getPropertyIds();
for (size_t ii = 0; ii < propertyIds.size(); ii++) {
_timelineIds.put(propertyIds[ii], true);
}
int boneIndex = -1;
if (timeline->getRTTI().instanceOf(BoneTimeline1::rtti)) {
boneIndex = static_cast<BoneTimeline1 *>(timeline)->getBoneIndex();
} else if (timeline->getRTTI().instanceOf(BoneTimeline2::rtti)) {
boneIndex = static_cast<BoneTimeline2 *>(timeline)->getBoneIndex();
}
if (boneIndex >= 0 && !boneSet.containsKey(boneIndex)) {
boneSet.put(boneIndex, true);
_bones.add(boneIndex);
}
}
}

View File

@ -1,82 +0,0 @@
/******************************************************************************
* 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 <spine/AnimationStateData.h>
#include <spine/Animation.h>
#include <spine/SkeletonData.h>
using namespace spine;
AnimationStateData::AnimationStateData(SkeletonData &skeletonData) : _skeletonData(&skeletonData), _defaultMix(0) {
}
void AnimationStateData::setMix(const String &fromName, const String &toName, float duration) {
Animation *from = _skeletonData->findAnimation(fromName);
Animation *to = _skeletonData->findAnimation(toName);
assert(from != NULL);
assert(to != NULL);
setMix(*from, *to, duration);
}
void AnimationStateData::setMix(Animation &from, Animation &to, float duration) {
AnimationPair key(&from, &to);
_animationToMixTime.put(key, duration);
}
float AnimationStateData::getMix(Animation &from, Animation &to) {
AnimationPair key(&from, &to);
if (_animationToMixTime.containsKey(key)) return _animationToMixTime[key];
return _defaultMix;
}
SkeletonData &AnimationStateData::getSkeletonData() {
return *_skeletonData;
}
float AnimationStateData::getDefaultMix() {
return _defaultMix;
}
void AnimationStateData::setDefaultMix(float inValue) {
_defaultMix = inValue;
}
void AnimationStateData::clear() {
_defaultMix = 0;
_animationToMixTime.clear();
}
AnimationStateData::AnimationPair::AnimationPair(Animation *a1, Animation *a2) : _a1(a1), _a2(a2) {
}
bool AnimationStateData::AnimationPair::operator==(const AnimationPair &other) const {
return _a1->_name == other._a1->_name && _a2->_name == other._a2->_name;
}

View File

@ -1,361 +0,0 @@
/******************************************************************************
* 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 <spine/Atlas.h>
#include <spine/ArrayUtils.h>
#include <spine/TextureLoader.h>
#include <ctype.h>
using namespace spine;
RTTI_IMPL(AtlasRegion, TextureRegion)
Atlas::Atlas(const String &path, TextureLoader *textureLoader, bool createTexture) : _textureLoader(textureLoader) {
int dirLength;
char *dir;
int length;
const char *data;
/* Get directory from atlas path. */
const char *lastForwardSlash = strrchr(path.buffer(), '/');
const char *lastBackwardSlash = strrchr(path.buffer(), '\\');
const char *lastSlash = lastForwardSlash > lastBackwardSlash ? lastForwardSlash : lastBackwardSlash;
if (lastSlash == path) lastSlash++; /* Never drop starting slash. */
dirLength = (int) (lastSlash ? lastSlash - path.buffer() : 0);
dir = SpineExtension::calloc<char>(dirLength + 1, __FILE__, __LINE__);
memcpy(dir, path.buffer(), dirLength);
dir[dirLength] = '\0';
data = SpineExtension::readFile(path, &length);
if (data) {
load(data, length, dir, createTexture);
}
SpineExtension::free(data, __FILE__, __LINE__);
SpineExtension::free(dir, __FILE__, __LINE__);
}
Atlas::Atlas(const char *data, int length, const char *dir, TextureLoader *textureLoader, bool createTexture) : _textureLoader(textureLoader) {
load(data, length, dir, createTexture);
}
Atlas::~Atlas() {
if (_textureLoader) {
for (size_t i = 0, n = _pages.size(); i < n; ++i) {
_textureLoader->unload(_pages[i]->texture);
}
}
ArrayUtils::deleteElements(_pages);
ArrayUtils::deleteElements(_regions);
}
void Atlas::flipV() {
for (size_t i = 0, n = _regions.size(); i < n; ++i) {
AtlasRegion *regionP = _regions[i];
AtlasRegion &region = *regionP;
region._v = 1 - region._v;
region._v2 = 1 - region._v2;
}
}
AtlasRegion *Atlas::findRegion(const String &name) {
for (size_t i = 0, n = _regions.size(); i < n; ++i)
if (_regions[i]->_name == name) return _regions[i];
return nullptr;
}
Array<AtlasPage *> &Atlas::getPages() {
return _pages;
}
Array<AtlasRegion *> &Atlas::getRegions() {
return _regions;
}
struct SimpleString {
char *start;
char *end;
int length;
SimpleString trim() {
while (isspace((unsigned char) *start) && start < end) start++;
if (start == end) {
length = (int) (end - start);
return *this;
}
end--;
while (((unsigned char) *end == '\r') && end >= start) end--;
end++;
length = (int) (end - start);
return *this;
}
int indexOf(char needle) {
char *c = start;
while (c < end) {
if (*c == needle) return (int) (c - start);
c++;
}
return -1;
}
int indexOf(char needle, int at) {
char *c = start + at;
while (c < end) {
if (*c == needle) return (int) (c - start);
c++;
}
return -1;
}
SimpleString substr(int s, int e) {
e = s + e;
SimpleString result;
result.start = start + s;
result.end = start + e;
result.length = e - s;
return result;
}
SimpleString substr(int s) {
SimpleString result;
result.start = start + s;
result.end = end;
result.length = (int) (result.end - result.start);
return result;
}
bool equals(const char *str) {
int otherLen = (int) strlen(str);
if (length != otherLen) return false;
for (int i = 0; i < length; i++) {
if (start[i] != str[i]) return false;
}
return true;
}
char *copy() {
char *string = SpineExtension::calloc<char>(length + 1, __FILE__, __LINE__);
memcpy(string, start, length);
string[length] = '\0';
return string;
}
int toInt() {
return (int) strtol(start, &end, 10);
}
};
struct AtlasInput {
const char *start;
const char *end;
char *index;
int length;
SimpleString line;
AtlasInput(const char *data, int length) : start(data), end(data + length), index((char *) data), length(length) {
}
SimpleString *readLine() {
if (index >= end) return 0;
line.start = index;
while (index < end && *index != '\n') index++;
line.end = index;
if (index != end) index++;
line = line.trim();
line.length = (int) (end - start);
return &line;
}
static int readEntry(SimpleString entry[5], SimpleString *line) {
if (line == nullptr) return 0;
line->trim();
if (line->length == 0) return 0;
int colon = line->indexOf(':');
if (colon == -1) return 0;
entry[0] = line->substr(0, colon).trim();
for (int i = 1, lastMatch = colon + 1;; i++) {
int comma = line->indexOf(',', lastMatch);
if (comma == -1) {
entry[i] = line->substr(lastMatch).trim();
return i;
}
entry[i] = line->substr(lastMatch, comma - lastMatch).trim();
lastMatch = comma + 1;
if (i == 4) return 4;
}
}
};
int indexOf(const char **array, int count, SimpleString *str) {
for (int i = 0; i < count; i++)
if (str->equals(array[i])) return i;
return 0;
}
void Atlas::load(const char *begin, int length, const char *dir, bool createTexture) {
static const char *formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888", "RGBA8888"};
static const char *textureFilterNames[] =
{"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest", "MipMapLinearNearest", "MipMapNearestLinear", "MipMapLinearLinear"};
int dirLength = (int) strlen(dir);
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
AtlasInput reader(begin, length);
SimpleString entry[5];
AtlasPage *page = nullptr;
SimpleString *line = reader.readLine();
while (line != nullptr && line->length == 0) line = reader.readLine();
while (true) {
if (line == nullptr || line->length == 0) break;
if (reader.readEntry(entry, line) == 0) break;
line = reader.readLine();
}
while (true) {
if (line == nullptr) break;
if (line->trim().length == 0) {
page = nullptr;
line = reader.readLine();
} else if (page == nullptr) {
char *name = line->copy();
char *path = SpineExtension::calloc<char>(dirLength + needsSlash + strlen(name) + 1, __FILE__, __LINE__);
memcpy(path, dir, dirLength);
if (needsSlash) path[dirLength] = '/';
strcpy(path + dirLength + needsSlash, name);
page = new (__FILE__, __LINE__) AtlasPage(String(name, true));
while (true) {
line = reader.readLine();
if (reader.readEntry(entry, line) == 0) break;
if (entry[0].equals("size")) {
page->width = entry[1].toInt();
page->height = entry[2].toInt();
} else if (entry[0].equals("format")) {
page->format = (Format) indexOf(formatNames, 8, &entry[1]);
} else if (entry[0].equals("filter")) {
#ifdef SPINE_UE4
page->minFilter = (SpineTextureFilter) indexOf(textureFilterNames, 8, &entry[1]);
page->magFilter = (SpineTextureFilter) indexOf(textureFilterNames, 8, &entry[2]);
#else
page->minFilter = (TextureFilter) indexOf(textureFilterNames, 8, &entry[1]);
page->magFilter = (TextureFilter) indexOf(textureFilterNames, 8, &entry[2]);
#endif
} else if (entry[0].equals("repeat")) {
page->uWrap = TextureWrap_ClampToEdge;
page->vWrap = TextureWrap_ClampToEdge;
if (entry[1].indexOf('x') != -1) page->uWrap = TextureWrap_Repeat;
if (entry[1].indexOf('y') != -1) page->vWrap = TextureWrap_Repeat;
} else if (entry[0].equals("pma")) {
page->pma = entry[1].equals("true");
}
}
page->index = (int) _pages.size();
if (createTexture && _textureLoader) _textureLoader->load(*page, String(path));
page->texturePath = String(path, true);
_pages.add(page);
} else {
AtlasRegion *region = new (__FILE__, __LINE__) AtlasRegion();
region->_page = page;
region->_rendererObject = page->texture;
region->_name = String(line->copy(), true);
while (true) {
line = reader.readLine();
int count = reader.readEntry(entry, line);
if (count == 0) break;
if (entry[0].equals("xy")) {
region->_x = entry[1].toInt();
region->_y = entry[2].toInt();
} else if (entry[0].equals("size")) {
region->_packedWidth = entry[1].toInt();
region->_packedHeight = entry[2].toInt();
} else if (entry[0].equals("bounds")) {
region->_x = entry[1].toInt();
region->_y = entry[2].toInt();
region->_packedWidth = entry[3].toInt();
region->_packedHeight = entry[4].toInt();
} else if (entry[0].equals("offset")) {
region->_offsetX = entry[1].toInt();
region->_offsetY = entry[2].toInt();
} else if (entry[0].equals("orig")) {
region->_originalWidth = entry[1].toInt();
region->_originalHeight = entry[2].toInt();
} else if (entry[0].equals("offsets")) {
region->_offsetX = entry[1].toInt();
region->_offsetY = entry[2].toInt();
region->_originalWidth = entry[3].toInt();
region->_originalHeight = entry[4].toInt();
} else if (entry[0].equals("rotate")) {
if (entry[1].equals("true")) {
region->_degrees = 90;
} else if (!entry[1].equals("false")) {
region->_degrees = entry[1].toInt();
}
region->_rotate = region->_degrees == 90;
} else if (entry[0].equals("index")) {
region->_index = entry[1].toInt();
} else {
region->_names.add(String(entry[0].copy()));
for (int i = 0; i < count; i++) {
region->_values.add(entry[i + 1].toInt());
}
}
}
if (region->_originalWidth == 0 && region->_originalHeight == 0) {
region->_originalWidth = region->_packedWidth;
region->_originalHeight = region->_packedHeight;
}
region->_u = (float) region->_x / page->width;
region->_v = (float) region->_y / page->height;
if (region->_degrees == 90) {
region->_u2 = (float) (region->_x + region->_packedHeight) / page->width;
region->_v2 = (float) (region->_y + region->_packedWidth) / page->height;
} else {
region->_u2 = (float) (region->_x + region->_packedWidth) / page->width;
region->_v2 = (float) (region->_y + region->_packedHeight) / page->height;
}
// Calculate regionWidth/Height from UV coordinates
region->_regionWidth = abs((int) ((region->_u2 - region->_u) * page->width));
region->_regionHeight = abs((int) ((region->_v2 - region->_v) * page->height));
if (region->_degrees == 90) {
int temp = region->_packedWidth;
region->_packedWidth = region->_packedHeight;
region->_packedHeight = temp;
}
_regions.add(region);
}
}
}

View File

@ -1,88 +0,0 @@
/******************************************************************************
* 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 <spine/AtlasAttachmentLoader.h>
#include <spine/BoundingBoxAttachment.h>
#include <spine/ClippingAttachment.h>
#include <spine/MeshAttachment.h>
#include <spine/PathAttachment.h>
#include <spine/PointAttachment.h>
#include <spine/RegionAttachment.h>
#include <spine/Skin.h>
#include <spine/Atlas.h>
using namespace spine;
AtlasAttachmentLoader::AtlasAttachmentLoader(Atlas &atlas) : AttachmentLoader(), _atlas(&atlas) {
}
static void findRegions(Atlas *atlas, AtlasAttachmentLoader *loader, const String &name, const String &basePath, Sequence *sequence) {
Array<TextureRegion *> &regions = sequence->getRegions();
for (int i = 0, n = (int) regions.size(); i < n; i++) {
String path = sequence->getPath(basePath, i);
regions[i] = loader->findRegion(path);
}
}
RegionAttachment *AtlasAttachmentLoader::newRegionAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) {
SP_UNUSED(skin);
findRegions(_atlas, this, name, path, sequence);
return new (__FILE__, __LINE__) RegionAttachment(name, sequence);
}
MeshAttachment *AtlasAttachmentLoader::newMeshAttachment(Skin &skin, const String &name, const String &path, Sequence *sequence) {
SP_UNUSED(skin);
findRegions(_atlas, this, name, path, sequence);
return new (__FILE__, __LINE__) MeshAttachment(name, sequence);
}
BoundingBoxAttachment *AtlasAttachmentLoader::newBoundingBoxAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) BoundingBoxAttachment(name);
}
PathAttachment *AtlasAttachmentLoader::newPathAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) PathAttachment(name);
}
PointAttachment *AtlasAttachmentLoader::newPointAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) PointAttachment(name);
}
ClippingAttachment *AtlasAttachmentLoader::newClippingAttachment(Skin &skin, const String &name) {
SP_UNUSED(skin);
return new (__FILE__, __LINE__) ClippingAttachment(name);
}
AtlasRegion *AtlasAttachmentLoader::findRegion(const String &name) {
return _atlas->findRegion(name);
}

View File

@ -1,67 +0,0 @@
/******************************************************************************
* 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 <spine/Attachment.h>
#include <assert.h>
using namespace spine;
RTTI_IMPL_NOPARENT(Attachment)
Attachment::Attachment(const String &name) : _name(name), _timelineAttachment(this), _refCount(0) {
assert(_name.length() > 0);
}
Attachment::~Attachment() {
}
const String &Attachment::getName() const {
return _name;
}
Attachment *Attachment::getTimelineAttachment() {
return _timelineAttachment;
}
void Attachment::setTimelineAttachment(Attachment *attachment) {
_timelineAttachment = attachment;
}
int Attachment::getRefCount() {
return _refCount;
}
void Attachment::reference() {
_refCount++;
}
void Attachment::dereference() {
_refCount--;
}

View File

@ -1,46 +0,0 @@
/******************************************************************************
* 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 <spine/AttachmentLoader.h>
#include <spine/BoundingBoxAttachment.h>
#include <spine/ClippingAttachment.h>
#include <spine/MeshAttachment.h>
#include <spine/PathAttachment.h>
#include <spine/PointAttachment.h>
#include <spine/RegionAttachment.h>
#include <spine/Skin.h>
using namespace spine;
AttachmentLoader::AttachmentLoader() {
}
AttachmentLoader::~AttachmentLoader() {
}

View File

@ -1,89 +0,0 @@
/******************************************************************************
* 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 <spine/AttachmentTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Bone.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/SlotPose.h>
using namespace spine;
RTTI_IMPL_MULTI(AttachmentTimeline, Timeline, SlotTimeline)
AttachmentTimeline::AttachmentTimeline(size_t frameCount, int slotIndex) : Timeline(frameCount, 1), SlotTimeline(), _slotIndex(slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Attachment << 32) | slotIndex};
setPropertyIds(ids, 1);
_instant = true;
_attachmentNames.ensureCapacity(frameCount);
for (size_t i = 0; i < frameCount; ++i) {
_attachmentNames.add(String());
}
}
AttachmentTimeline::~AttachmentTimeline() {
}
void AttachmentTimeline::setAttachment(Skeleton &skeleton, SlotPose &pose, String *attachmentName) {
pose.setAttachment(attachmentName == NULL || attachmentName->isEmpty() ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName));
}
void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add,
bool out, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(alpha);
SP_UNUSED(add);
Slot *slot = skeleton._slots[_slotIndex];
if (!slot->_bone.isActive()) return;
SlotPose &pose = appliedPose ? *slot->_applied : slot->_pose;
if (out || time < _frames[0]) {
if (fromSetup) setAttachment(skeleton, pose, &slot->_data._attachmentName);
} else {
setAttachment(skeleton, pose, &_attachmentNames[Animation::search(_frames, time)]);
}
}
void AttachmentTimeline::setFrame(int frame, float time, const String &attachmentName) {
_frames[frame] = time;
_attachmentNames[frame] = attachmentName;
}
Array<String> &AttachmentTimeline::getAttachmentNames() {
return _attachmentNames;
}

View File

@ -1,60 +0,0 @@
/******************************************************************************
* 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 <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/BoneLocal.h>
#include <spine/BonePose.h>
using namespace spine;
RTTI_IMPL(Bone, Update)
bool Bone::yDown = true;
Bone::Bone(BoneData &data, Bone *parent)
: PosedGeneric<BoneData, BoneLocal, BonePose>(data), PosedActive(), _parent(parent), _children(), _sorted(false) {
_constrained._bone = this;
_applied->_bone = this;
}
Bone::Bone(Bone &bone, Bone *parent)
: PosedGeneric<BoneData, BoneLocal, BonePose>(bone._data), PosedActive(), _parent(parent), _children(), _sorted(false) {
_constrained._bone = this;
_applied->_bone = this;
_pose.set(bone._pose);
}
Bone *Bone::getParent() {
return _parent;
}
Array<Bone *> &Bone::getChildren() {
return _children;
}

View File

@ -1,75 +0,0 @@
/******************************************************************************
* 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 <spine/BoneData.h>
#include <assert.h>
using namespace spine;
BoneData::BoneData(int index, const String &name, BoneData *parent)
: PosedDataGeneric<BoneLocal>(name), _index(index), _parent(parent), _length(0), _color(0.61f, 0.61f, 0.61f, 1.0f), _icon(), _visible(true) {
assert(index >= 0);
}
int BoneData::getIndex() {
return _index;
}
BoneData *BoneData::getParent() {
return _parent;
}
float BoneData::getLength() {
return _length;
}
void BoneData::setLength(float inValue) {
_length = inValue;
}
Color &BoneData::getColor() {
return _color;
}
const String &BoneData::getIcon() {
return _icon;
}
void BoneData::setIcon(const String &icon) {
this->_icon = icon;
}
bool BoneData::getVisible() {
return _visible;
}
void BoneData::setVisible(bool inValue) {
this->_visible = inValue;
}

View File

@ -1,128 +0,0 @@
/******************************************************************************
* 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 <spine/BoneLocal.h>
using namespace spine;
BoneLocal::BoneLocal() : _x(0), _y(0), _rotation(0), _scaleX(1), _scaleY(1), _shearX(0), _shearY(0), _inherit(Inherit_Normal) {
}
BoneLocal::~BoneLocal() {
}
void BoneLocal::set(BoneLocal &pose) {
_x = pose._x;
_y = pose._y;
_rotation = pose._rotation;
_scaleX = pose._scaleX;
_scaleY = pose._scaleY;
_shearX = pose._shearX;
_shearY = pose._shearY;
_inherit = pose._inherit;
}
float BoneLocal::getX() {
return _x;
}
void BoneLocal::setX(float x) {
_x = x;
}
float BoneLocal::getY() {
return _y;
}
void BoneLocal::setY(float y) {
_y = y;
}
void BoneLocal::setPosition(float x, float y) {
_x = x;
_y = y;
}
float BoneLocal::getRotation() {
return _rotation;
}
void BoneLocal::setRotation(float rotation) {
_rotation = rotation;
}
float BoneLocal::getScaleX() {
return _scaleX;
}
void BoneLocal::setScaleX(float scaleX) {
_scaleX = scaleX;
}
float BoneLocal::getScaleY() {
return _scaleY;
}
void BoneLocal::setScaleY(float scaleY) {
_scaleY = scaleY;
}
void BoneLocal::setScale(float scaleX, float scaleY) {
_scaleX = scaleX;
_scaleY = scaleY;
}
void BoneLocal::setScale(float scale) {
_scaleX = scale;
_scaleY = scale;
}
float BoneLocal::getShearX() {
return _shearX;
}
void BoneLocal::setShearX(float shearX) {
_shearX = shearX;
}
float BoneLocal::getShearY() {
return _shearY;
}
void BoneLocal::setShearY(float shearY) {
_shearY = shearY;
}
Inherit BoneLocal::getInherit() {
return _inherit;
}
void BoneLocal::setInherit(Inherit inherit) {
_inherit = inherit;
}

View File

@ -1,388 +0,0 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 <spine/BonePose.h>
#include "spine/RTTI.h"
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/Skeleton.h>
#include <spine/Physics.h>
#include <spine/MathUtil.h>
using namespace spine;
RTTI_IMPL(BonePose, Update);
BonePose::BonePose() : BoneLocal(), _bone(nullptr), _a(0), _b(0), _worldX(0), _c(0), _d(0), _worldY(0), _world(0), _local(0) {
}
BonePose::~BonePose() {
}
void BonePose::update(Skeleton &skeleton, Physics physics) {
if (_world != skeleton._update) updateWorldTransform(skeleton);
}
void BonePose::updateWorldTransform(Skeleton &skeleton) {
if (_local == skeleton._update)
updateLocalTransform(skeleton);
else
_world = skeleton._update;
if (_bone->getParent() == nullptr) {// Root bone.
float sx = skeleton.getScaleX(), sy = skeleton.getScaleY();
float rx = (_rotation + _shearX) * MathUtil::Deg_Rad;
float ry = (_rotation + 90 + _shearY) * MathUtil::Deg_Rad;
_a = MathUtil::cos(rx) * _scaleX * sx;
_b = MathUtil::cos(ry) * _scaleY * sx;
_c = MathUtil::sin(rx) * _scaleX * sy;
_d = MathUtil::sin(ry) * _scaleY * sy;
_worldX = _x * sx + skeleton.getX();
_worldY = _y * sy + skeleton.getY();
return;
}
BonePose &parent = _bone->getParent()->getAppliedPose();
float pa = parent._a, pb = parent._b, pc = parent._c, pd = parent._d;
_worldX = pa * _x + pb * _y + parent._worldX;
_worldY = pc * _x + pd * _y + parent._worldY;
switch (_inherit) {
case Inherit_Normal: {
float rx = (_rotation + _shearX) * MathUtil::Deg_Rad;
float ry = (_rotation + 90 + _shearY) * MathUtil::Deg_Rad;
float la = MathUtil::cos(rx) * _scaleX;
float lb = MathUtil::cos(ry) * _scaleY;
float lc = MathUtil::sin(rx) * _scaleX;
float ld = MathUtil::sin(ry) * _scaleY;
_a = pa * la + pb * lc;
_b = pa * lb + pb * ld;
_c = pc * la + pd * lc;
_d = pc * lb + pd * ld;
return;
}
case Inherit_OnlyTranslation: {
float rx = (_rotation + _shearX) * MathUtil::Deg_Rad;
float ry = (_rotation + 90 + _shearY) * MathUtil::Deg_Rad;
_a = MathUtil::cos(rx) * _scaleX;
_b = MathUtil::cos(ry) * _scaleY;
_c = MathUtil::sin(rx) * _scaleX;
_d = MathUtil::sin(ry) * _scaleY;
break;
}
case Inherit_NoRotationOrReflection: {
float sx = 1 / skeleton.getScaleX(), sy = 1 / skeleton.getScaleY();
pa *= sx;
pc *= sy;
float s = pa * pa + pc * pc, prx;
if (s > 0.0001f) {
s = MathUtil::abs(pa * pd * sy - pb * sx * pc) / s;
pb = pc * s;
pd = pa * s;
prx = MathUtil::atan2(pc, pa) * MathUtil::Rad_Deg;
} else {
pa = 0;
pc = 0;
prx = 90 - MathUtil::atan2(pd, pb) * MathUtil::Rad_Deg;
}
float rx = (_rotation + _shearX - prx) * MathUtil::Deg_Rad;
float ry = (_rotation + _shearY - prx + 90) * MathUtil::Deg_Rad;
float la = MathUtil::cos(rx) * _scaleX;
float lb = MathUtil::cos(ry) * _scaleY;
float lc = MathUtil::sin(rx) * _scaleX;
float ld = MathUtil::sin(ry) * _scaleY;
_a = pa * la - pb * lc;
_b = pa * lb - pb * ld;
_c = pc * la + pd * lc;
_d = pc * lb + pd * ld;
break;
}
case Inherit_NoScale:
case Inherit_NoScaleOrReflection: {
float r = _rotation * MathUtil::Deg_Rad, cosR = MathUtil::cos(r), sinR = MathUtil::sin(r);
float za = (pa * cosR + pb * sinR) / skeleton.getScaleX();
float zc = (pc * cosR + pd * sinR) / skeleton.getScaleY();
float s = MathUtil::sqrt(za * za + zc * zc);
if (s > 0.00001f) s = 1 / s;
za *= s;
zc *= s;
s = MathUtil::sqrt(za * za + zc * zc);
if (_inherit == Inherit_NoScale && (pa * pd - pb * pc < 0) != ((skeleton.getScaleX() < 0) != (skeleton.getScaleY() < 0))) s = -s;
r = MathUtil::Pi / 2 + MathUtil::atan2(zc, za);
float zb = MathUtil::cos(r) * s;
float zd = MathUtil::sin(r) * s;
float rx = _shearX * MathUtil::Deg_Rad;
float ry = (90 + _shearY) * MathUtil::Deg_Rad;
float la = MathUtil::cos(rx) * _scaleX;
float lb = MathUtil::cos(ry) * _scaleY;
float lc = MathUtil::sin(rx) * _scaleX;
float ld = MathUtil::sin(ry) * _scaleY;
_a = za * la + zb * lc;
_b = za * lb + zb * ld;
_c = zc * la + zd * lc;
_d = zc * lb + zd * ld;
break;
}
}
_a *= skeleton.getScaleX();
_b *= skeleton.getScaleX();
_c *= skeleton.getScaleY();
_d *= skeleton.getScaleY();
}
void BonePose::updateLocalTransform(Skeleton &skeleton) {
_local = 0;
_world = skeleton._update;
if (_bone->getParent() == nullptr) {
_x = _worldX - skeleton.getX();
_y = _worldY - skeleton.getY();
float a = this->_a, b = this->_b, c = this->_c, d = this->_d;
_rotation = MathUtil::atan2(c, a) * MathUtil::Rad_Deg;
_scaleX = MathUtil::sqrt(a * a + c * c);
_scaleY = MathUtil::sqrt(b * b + d * d);
_shearX = 0;
_shearY = MathUtil::atan2(a * b + c * d, a * d - b * c) * MathUtil::Rad_Deg;
return;
}
BonePose &parent = _bone->getParent()->getAppliedPose();
float pa = parent._a, pb = parent._b, pc = parent._c, pd = parent._d;
float pid = 1 / (pa * pd - pb * pc);
float ia = pd * pid, ib = pb * pid, ic = pc * pid, id = pa * pid;
float dx = _worldX - parent._worldX, dy = _worldY - parent._worldY;
_x = (dx * ia - dy * ib);
_y = (dy * id - dx * ic);
float ra, rb, rc, rd;
if (_inherit == Inherit_OnlyTranslation) {
ra = _a;
rb = _b;
rc = _c;
rd = _d;
} else {
switch (_inherit) {
case Inherit_NoRotationOrReflection: {
float s = MathUtil::abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
pb = -pc * skeleton.getScaleX() * s / skeleton.getScaleY();
pd = pa * skeleton.getScaleY() * s / skeleton.getScaleX();
pid = 1 / (pa * pd - pb * pc);
ia = pd * pid;
ib = pb * pid;
break;
}
case Inherit_NoScale:
case Inherit_NoScaleOrReflection: {
float r = _rotation * MathUtil::Deg_Rad, cosR = MathUtil::cos(r), sinR = MathUtil::sin(r);
pa = (pa * cosR + pb * sinR) / skeleton.getScaleX();
pc = (pc * cosR + pd * sinR) / skeleton.getScaleY();
float s = MathUtil::sqrt(pa * pa + pc * pc);
if (s > 0.00001f) s = 1 / s;
pa *= s;
pc *= s;
s = MathUtil::sqrt(pa * pa + pc * pc);
if (_inherit == Inherit_NoScale && (pid < 0) != ((skeleton.getScaleX() < 0) != (skeleton.getScaleY() < 0))) s = -s;
r = MathUtil::Pi / 2 + MathUtil::atan2(pc, pa);
pb = MathUtil::cos(r) * s;
pd = MathUtil::sin(r) * s;
pid = 1 / (pa * pd - pb * pc);
ia = pd * pid;
ib = pb * pid;
ic = pc * pid;
id = pa * pid;
break;
}
default:
break;
}
ra = ia * _a - ib * _c;
rb = ia * _b - ib * _d;
rc = id * _c - ic * _a;
rd = id * _d - ic * _b;
}
_shearX = 0;
_scaleX = MathUtil::sqrt(ra * ra + rc * rc);
if (_scaleX > 0.0001f) {
float det = ra * rd - rb * rc;
_scaleY = det / _scaleX;
_shearY = -MathUtil::atan2(ra * rb + rc * rd, det) * MathUtil::Rad_Deg;
_rotation = MathUtil::atan2(rc, ra) * MathUtil::Rad_Deg;
} else {
_scaleX = 0;
_scaleY = MathUtil::sqrt(rb * rb + rd * rd);
_shearY = 0;
_rotation = 90 - MathUtil::atan2(rd, rb) * MathUtil::Rad_Deg;
}
}
void BonePose::validateLocalTransform(Skeleton &skeleton) {
if (_local == skeleton._update) updateLocalTransform(skeleton);
}
void BonePose::modifyLocal(Skeleton &skeleton) {
if (_local == skeleton._update) updateLocalTransform(skeleton);
_world = 0;
resetWorld(skeleton._update);
}
void BonePose::modifyWorld(int update) {
_local = update;
_world = update;
resetWorld(update);
}
void BonePose::resetWorld(int update) {
Array<Bone *> &children = _bone->getChildren();
for (size_t i = 0, n = children.size(); i < n; i++) {
BonePose &child = children[i]->getAppliedPose();
if (child._world == update) {
child._world = 0;
child._local = 0;
child.resetWorld(update);
}
}
}
float BonePose::getA() {
return _a;
}
void BonePose::setA(float a) {
this->_a = a;
}
float BonePose::getB() {
return _b;
}
void BonePose::setB(float b) {
this->_b = b;
}
float BonePose::getC() {
return _c;
}
void BonePose::setC(float c) {
this->_c = c;
}
float BonePose::getD() {
return _d;
}
void BonePose::setD(float d) {
this->_d = d;
}
float BonePose::getWorldX() {
return _worldX;
}
void BonePose::setWorldX(float worldX) {
this->_worldX = worldX;
}
float BonePose::getWorldY() {
return _worldY;
}
void BonePose::setWorldY(float worldY) {
this->_worldY = worldY;
}
float BonePose::getWorldRotationX() {
return MathUtil::atan2(_c, _a) * MathUtil::Rad_Deg;
}
float BonePose::getWorldRotationY() {
return MathUtil::atan2(_d, _b) * MathUtil::Rad_Deg;
}
float BonePose::getWorldScaleX() {
return MathUtil::sqrt(_a * _a + _c * _c);
}
float BonePose::getWorldScaleY() {
return MathUtil::sqrt(_b * _b + _d * _d);
}
void BonePose::worldToLocal(float worldX, float worldY, float &outLocalX, float &outLocalY) {
float det = _a * _d - _b * _c;
float x = worldX - _worldX, y = worldY - _worldY;
outLocalX = (x * _d - y * _b) / det;
outLocalY = (y * _a - x * _c) / det;
}
void BonePose::localToWorld(float localX, float localY, float &outWorldX, float &outWorldY) {
outWorldX = localX * _a + localY * _b + _worldX;
outWorldY = localX * _c + localY * _d + _worldY;
}
void BonePose::worldToParent(float worldX, float worldY, float &outParentX, float &outParentY) {
if (_bone->getParent() == nullptr) {
outParentX = worldX;
outParentY = worldY;
} else {
_bone->getParent()->getAppliedPose().worldToLocal(worldX, worldY, outParentX, outParentY);
}
}
void BonePose::parentToWorld(float parentX, float parentY, float &outWorldX, float &outWorldY) {
if (_bone->getParent() == nullptr) {
outWorldX = parentX;
outWorldY = parentY;
} else {
_bone->getParent()->getAppliedPose().localToWorld(parentX, parentY, outWorldX, outWorldY);
}
}
float BonePose::worldToLocalRotation(float worldRotation) {
worldRotation *= MathUtil::Deg_Rad;
float sinRot = MathUtil::sin(worldRotation), cosRot = MathUtil::cos(worldRotation);
return MathUtil::atan2(_a * sinRot - _c * cosRot, _d * cosRot - _b * sinRot) * MathUtil::Rad_Deg + _rotation - _shearX;
}
float BonePose::localToWorldRotation(float localRotation) {
localRotation = (localRotation - _rotation - _shearX) * MathUtil::Deg_Rad;
float sinRot = MathUtil::sin(localRotation), cosRot = MathUtil::cos(localRotation);
return MathUtil::atan2(cosRot * _c + sinRot * _d, cosRot * _a + sinRot * _b) * MathUtil::Rad_Deg;
}
void BonePose::rotateWorld(float degrees) {
degrees *= MathUtil::Deg_Rad;
float sinRot = MathUtil::sin(degrees), cosRot = MathUtil::cos(degrees);
float ra = _a, rb = _b;
_a = cosRot * ra - sinRot * _c;
_b = cosRot * rb - sinRot * _d;
_c = sinRot * ra + cosRot * _c;
_d = sinRot * rb + cosRot * _d;
}

View File

@ -1,93 +0,0 @@
/******************************************************************************
* 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 <spine/BoneTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/BoneLocal.h>
#include <spine/Property.h>
using namespace spine;
// Define static constants for BoneTimeline2
const int BoneTimeline2::ENTRIES = 3;
const int BoneTimeline2::VALUE1 = 1;
const int BoneTimeline2::VALUE2 = 2;
RTTI_IMPL_NOPARENT(BoneTimeline)
RTTI_IMPL_MULTI(BoneTimeline1, CurveTimeline1, BoneTimeline)
BoneTimeline1::BoneTimeline1(size_t frameCount, size_t bezierCount, int boneIndex, Property property)
: CurveTimeline1(frameCount, bezierCount), BoneTimeline(boneIndex), _boneIndex(boneIndex) {
PropertyId ids[] = {((PropertyId) property << 32) | boneIndex};
setPropertyIds(ids, 1);
_additive = true;
}
void BoneTimeline1::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
Bone *bone = skeleton._bones[_boneIndex];
if (bone->isActive()) {
_apply(appliedPose ? *bone->_applied : bone->_pose, bone->_data._setup, time, alpha, fromSetup, add, out);
}
}
RTTI_IMPL_MULTI(BoneTimeline2, CurveTimeline, BoneTimeline)
BoneTimeline2::BoneTimeline2(size_t frameCount, size_t bezierCount, int boneIndex, Property property1, Property property2)
: CurveTimeline(frameCount, BoneTimeline2::ENTRIES, bezierCount), BoneTimeline(boneIndex), _boneIndex(boneIndex) {
PropertyId ids[] = {((PropertyId) property1 << 32) | boneIndex, ((PropertyId) property2 << 32) | boneIndex};
setPropertyIds(ids, 2);
_additive = true;
}
void BoneTimeline2::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
Bone *bone = skeleton._bones[_boneIndex];
if (bone->isActive()) {
_apply(appliedPose ? *bone->_applied : bone->_pose, bone->_data._setup, time, alpha, fromSetup, add, out);
}
}
void BoneTimeline2::setFrame(size_t frame, float time, float value1, float value2) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + VALUE1] = value1;
_frames[frame + VALUE2] = value2;
}

View File

@ -1,47 +0,0 @@
/******************************************************************************
* 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 <spine/BoundingBoxAttachment.h>
using namespace spine;
RTTI_IMPL(BoundingBoxAttachment, VertexAttachment)
BoundingBoxAttachment::BoundingBoxAttachment(const String &name) : VertexAttachment(name), _color(0.38f, 0.94f, 0.0f, 1.0f) {
}
Color &BoundingBoxAttachment::getColor() {
return _color;
}
Attachment &BoundingBoxAttachment::copy() {
BoundingBoxAttachment *copy = new (__FILE__, __LINE__) BoundingBoxAttachment(getName());
copyTo(*copy);
return *copy;
}

View File

@ -1,58 +0,0 @@
/******************************************************************************
* 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 <spine/ClippingAttachment.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(ClippingAttachment, VertexAttachment)
ClippingAttachment::ClippingAttachment(const String &name) : VertexAttachment(name), _endSlot(NULL), _color() {
}
SlotData *ClippingAttachment::getEndSlot() {
return _endSlot;
}
void ClippingAttachment::setEndSlot(SlotData *inValue) {
_endSlot = inValue;
}
Color &ClippingAttachment::getColor() {
return _color;
}
Attachment &ClippingAttachment::copy() {
ClippingAttachment *copy = new (__FILE__, __LINE__) ClippingAttachment(getName());
copyTo(*copy);
copy->_endSlot = _endSlot;
return *copy;
}

View File

@ -1,454 +0,0 @@
/******************************************************************************
* 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 <spine/ColorTimeline.h>
#include <spine/Animation.h>
#include <spine/Bone.h>
#include <spine/Event.h>
#include <spine/Property.h>
#include <spine/Skeleton.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/SlotPose.h>
using namespace spine;
RTTI_IMPL(RGBATimeline, SlotCurveTimeline)
RGBATimeline::RGBATimeline(size_t frameCount, size_t bezierCount, int slotIndex) : SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex, ((PropertyId) Property_Alpha << 32) | slotIndex};
setPropertyIds(ids, 2);
}
RGBATimeline::~RGBATimeline() {
}
void RGBATimeline::setFrame(int frame, float time, float r, float g, float b, float a) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + R] = r;
_frames[frame + G] = g;
_frames[frame + B] = b;
_frames[frame + A] = a;
}
void RGBATimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) {
SP_UNUSED(add);
Color &color = pose._color;
if (time < _frames[0]) {
if (fromSetup) color.set(slot._data._setup._color);
return;
}
float r, g, b, a;
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i / ENTRIES];
switch (curveType) {
case LINEAR: {
float before = _frames[i];
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
a = _frames[i + A];
float t = (time - before) / (_frames[i + ENTRIES] - before);
r += (_frames[i + ENTRIES + R] - r) * t;
g += (_frames[i + ENTRIES + G] - g) * t;
b += (_frames[i + ENTRIES + B] - b) * t;
a += (_frames[i + ENTRIES + A] - a) * t;
break;
}
case STEPPED: {
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
a = _frames[i + A];
break;
}
default: {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
a = getBezierValue(time, i, A, curveType + BEZIER_SIZE * 3 - BEZIER);
break;
}
}
if (alpha == 1)
color.set(r, g, b, a);
else {
if (fromSetup) {
Color &setup = slot._data._setup._color;
color.set(setup.r + (r - setup.r) * alpha, setup.g + (g - setup.g) * alpha, setup.b + (b - setup.b) * alpha,
setup.a + (a - setup.a) * alpha);
} else
color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
}
}
RTTI_IMPL(RGBTimeline, SlotCurveTimeline)
RGBTimeline::RGBTimeline(size_t frameCount, size_t bezierCount, int slotIndex) : SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex};
setPropertyIds(ids, 1);
}
RGBTimeline::~RGBTimeline() {
}
void RGBTimeline::setFrame(int frame, float time, float r, float g, float b) {
frame <<= 2;
_frames[frame] = time;
_frames[frame + R] = r;
_frames[frame + G] = g;
_frames[frame + B] = b;
}
void RGBTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) {
SP_UNUSED(add);
Color &color = pose._color;
float r, g, b;
if (time < _frames[0]) {
if (fromSetup) {
Color &setup = slot._data._setup._color;
color.r = setup.r;
color.g = setup.g;
color.b = setup.b;
}
return;
}
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i >> 2];
switch (curveType) {
case LINEAR: {
float before = _frames[i];
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
float t = (time - before) / (_frames[i + ENTRIES] - before);
r += (_frames[i + ENTRIES + R] - r) * t;
g += (_frames[i + ENTRIES + G] - g) * t;
b += (_frames[i + ENTRIES + B] - b) * t;
break;
}
case STEPPED: {
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
break;
}
default: {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
break;
}
}
if (alpha != 1) {
if (fromSetup) {
Color &setup = slot._data._setup._color;
r = setup.r + (r - setup.r) * alpha;
g = setup.g + (g - setup.g) * alpha;
b = setup.b + (b - setup.b) * alpha;
} else {
r = color.r + (r - color.r) * alpha;
g = color.g + (g - color.g) * alpha;
b = color.b + (b - color.b) * alpha;
}
}
color.r = r < 0 ? 0 : (r > 1 ? 1 : r);
color.g = g < 0 ? 0 : (g > 1 ? 1 : g);
color.b = b < 0 ? 0 : (b > 1 ? 1 : b);
}
RTTI_IMPL(AlphaTimeline, SlotCurveTimeline)
AlphaTimeline::AlphaTimeline(size_t frameCount, size_t bezierCount, int slotIndex)
: CurveTimeline1(frameCount, bezierCount), SlotTimeline(), _slotIndex(slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Alpha << 32) | slotIndex};
setPropertyIds(ids, 1);
}
AlphaTimeline::~AlphaTimeline() {
}
int AlphaTimeline::getSlotIndex() {
return _slotIndex;
}
void AlphaTimeline::setSlotIndex(int inValue) {
_slotIndex = inValue;
}
void AlphaTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(add);
SP_UNUSED(out);
Slot *slot = skeleton._slots[_slotIndex];
if (!slot->_bone._active) return;
Color &color = (appliedPose ? *slot->_applied : slot->_pose)._color;
if (time < _frames[0]) {
if (fromSetup) color.a = slot->_data._setup._color.a;
return;
}
float a = getCurveValue(time);
if (alpha != 1) {
if (fromSetup) {
Color &setup = slot->_data._setup._color;
a = setup.a + (a - setup.a) * alpha;
} else
a = color.a + (a - color.a) * alpha;
}
color.a = a < 0 ? 0 : (a > 1 ? 1 : a);
}
RTTI_IMPL(RGBA2Timeline, SlotCurveTimeline)
RGBA2Timeline::RGBA2Timeline(size_t frameCount, size_t bezierCount, int slotIndex) : SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex, ((PropertyId) Property_Alpha << 32) | slotIndex,
((PropertyId) Property_Rgb2 << 32) | slotIndex};
setPropertyIds(ids, 3);
}
RGBA2Timeline::~RGBA2Timeline() {
}
void RGBA2Timeline::setFrame(int frame, float time, float r, float g, float b, float a, float r2, float g2, float b2) {
frame <<= 3;
_frames[frame] = time;
_frames[frame + R] = r;
_frames[frame + G] = g;
_frames[frame + B] = b;
_frames[frame + A] = a;
_frames[frame + R2] = r2;
_frames[frame + G2] = g2;
_frames[frame + B2] = b2;
}
void RGBA2Timeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) {
SP_UNUSED(add);
Color &light = pose._color;
Color &dark = pose._darkColor;
float r2, g2, b2;
if (time < _frames[0]) {
if (fromSetup) {
SlotPose &setup = slot._data._setup;
light.set(setup._color);
Color &setupDark = setup._darkColor;
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
}
return;
}
float r, g, b, a;
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i >> 3];
switch (curveType) {
case LINEAR: {
float before = _frames[i];
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
a = _frames[i + A];
r2 = _frames[i + R2];
g2 = _frames[i + G2];
b2 = _frames[i + B2];
float t = (time - before) / (_frames[i + ENTRIES] - before);
r += (_frames[i + ENTRIES + R] - r) * t;
g += (_frames[i + ENTRIES + G] - g) * t;
b += (_frames[i + ENTRIES + B] - b) * t;
a += (_frames[i + ENTRIES + A] - a) * t;
r2 += (_frames[i + ENTRIES + R2] - r2) * t;
g2 += (_frames[i + ENTRIES + G2] - g2) * t;
b2 += (_frames[i + ENTRIES + B2] - b2) * t;
break;
}
case STEPPED: {
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
a = _frames[i + A];
r2 = _frames[i + R2];
g2 = _frames[i + G2];
b2 = _frames[i + B2];
break;
}
default: {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
a = getBezierValue(time, i, A, curveType + BEZIER_SIZE * 3 - BEZIER);
r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 4 - BEZIER);
g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 5 - BEZIER);
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 6 - BEZIER);
break;
}
}
if (alpha == 1)
light.set(r, g, b, a);
else if (fromSetup) {
SlotPose &setup = slot._data._setup;
Color &setupLight = setup._color;
light.set(setupLight.r + (r - setupLight.r) * alpha, setupLight.g + (g - setupLight.g) * alpha, setupLight.b + (b - setupLight.b) * alpha,
setupLight.a + (a - setupLight.a) * alpha);
Color &setupDark = setup._darkColor;
r2 = setupDark.r + (r2 - setupDark.r) * alpha;
g2 = setupDark.g + (g2 - setupDark.g) * alpha;
b2 = setupDark.b + (b2 - setupDark.b) * alpha;
} else {
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
r2 = dark.r + (r2 - dark.r) * alpha;
g2 = dark.g + (g2 - dark.g) * alpha;
b2 = dark.b + (b2 - dark.b) * alpha;
}
dark.r = r2 < 0 ? 0 : (r2 > 1 ? 1 : r2);
dark.g = g2 < 0 ? 0 : (g2 > 1 ? 1 : g2);
dark.b = b2 < 0 ? 0 : (b2 > 1 ? 1 : b2);
}
RTTI_IMPL(RGB2Timeline, SlotCurveTimeline)
RGB2Timeline::RGB2Timeline(size_t frameCount, size_t bezierCount, int slotIndex) : SlotCurveTimeline(frameCount, ENTRIES, bezierCount, slotIndex) {
PropertyId ids[] = {((PropertyId) Property_Rgb << 32) | slotIndex, ((PropertyId) Property_Rgb2 << 32) | slotIndex};
setPropertyIds(ids, 2);
}
RGB2Timeline::~RGB2Timeline() {
}
void RGB2Timeline::setFrame(int frame, float time, float r, float g, float b, float r2, float g2, float b2) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + R] = r;
_frames[frame + G] = g;
_frames[frame + B] = b;
_frames[frame + R2] = r2;
_frames[frame + G2] = g2;
_frames[frame + B2] = b2;
}
void RGB2Timeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) {
SP_UNUSED(add);
Color &light = pose._color;
Color &dark = pose._darkColor;
float r, g, b, r2, g2, b2;
if (time < _frames[0]) {
if (fromSetup) {
SlotPose &setup = slot._data._setup;
Color &setupLight = setup._color;
Color &setupDark = setup._darkColor;
light.r = setupLight.r;
light.g = setupLight.g;
light.b = setupLight.b;
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
}
return;
}
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i / ENTRIES];
switch (curveType) {
case LINEAR: {
float before = _frames[i];
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
r2 = _frames[i + R2];
g2 = _frames[i + G2];
b2 = _frames[i + B2];
float t = (time - before) / (_frames[i + ENTRIES] - before);
r += (_frames[i + ENTRIES + R] - r) * t;
g += (_frames[i + ENTRIES + G] - g) * t;
b += (_frames[i + ENTRIES + B] - b) * t;
r2 += (_frames[i + ENTRIES + R2] - r2) * t;
g2 += (_frames[i + ENTRIES + G2] - g2) * t;
b2 += (_frames[i + ENTRIES + B2] - b2) * t;
break;
}
case STEPPED: {
r = _frames[i + R];
g = _frames[i + G];
b = _frames[i + B];
r2 = _frames[i + R2];
g2 = _frames[i + G2];
b2 = _frames[i + B2];
break;
}
default: {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 3 - BEZIER);
g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 4 - BEZIER);
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 5 - BEZIER);
break;
}
}
if (alpha != 1) {
if (fromSetup) {
SlotPose &setup = slot._data._setup;
Color &setupLight = setup._color;
r = setupLight.r + (r - setupLight.r) * alpha;
g = setupLight.g + (g - setupLight.g) * alpha;
b = setupLight.b + (b - setupLight.b) * alpha;
Color &setupDark = setup._darkColor;
r2 = setupDark.r + (r2 - setupDark.r) * alpha;
g2 = setupDark.g + (g2 - setupDark.g) * alpha;
b2 = setupDark.b + (b2 - setupDark.b) * alpha;
} else {
r = light.r + (r - light.r) * alpha;
g = light.g + (g - light.g) * alpha;
b = light.b + (b - light.b) * alpha;
r2 = dark.r + (r2 - dark.r) * alpha;
g2 = dark.g + (g2 - dark.g) * alpha;
b2 = dark.b + (b2 - dark.b) * alpha;
}
}
light.r = r < 0 ? 0 : (r > 1 ? 1 : r);
light.g = g < 0 ? 0 : (g > 1 ? 1 : g);
light.b = b < 0 ? 0 : (b > 1 ? 1 : b);
dark.r = r2 < 0 ? 0 : (r2 > 1 ? 1 : r2);
dark.g = g2 < 0 ? 0 : (g2 > 1 ? 1 : g2);
dark.b = b2 < 0 ? 0 : (b2 > 1 ? 1 : b2);
}

View File

@ -1,40 +0,0 @@
/******************************************************************************
* 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 <spine/Constraint.h>
using namespace spine;
RTTI_IMPL(Constraint, Update)
Constraint::Constraint() {
}
Constraint::~Constraint() {
}

View File

@ -1,34 +0,0 @@
/******************************************************************************
* 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 <spine/ConstraintData.h>
using namespace spine;
RTTI_IMPL_NOPARENT(ConstraintData)

View File

@ -1,40 +0,0 @@
/******************************************************************************
* 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 <spine/ConstraintTimeline.h>
using namespace spine;
RTTI_IMPL_NOPARENT(ConstraintTimeline)
ConstraintTimeline::ConstraintTimeline() {
}
ConstraintTimeline::~ConstraintTimeline() {
}

View File

@ -1,43 +0,0 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 <spine/ConstraintTimeline1.h>
using namespace spine;
RTTI_IMPL_MULTI(ConstraintTimeline1, CurveTimeline1, ConstraintTimeline)
ConstraintTimeline1::ConstraintTimeline1(size_t frameCount, size_t bezierCount, int constraintIndex, Property property)
: CurveTimeline1(frameCount, bezierCount), ConstraintTimeline(), _constraintIndex(constraintIndex) {
PropertyId ids[] = {((PropertyId) property << 32) | constraintIndex};
setPropertyIds(ids, 1);
}
ConstraintTimeline1::~ConstraintTimeline1() {
}

View File

@ -1,159 +0,0 @@
/******************************************************************************
* 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 <spine/CurveTimeline.h>
#include <spine/MathUtil.h>
using namespace spine;
RTTI_IMPL(CurveTimeline, Timeline)
CurveTimeline::CurveTimeline(size_t frameCount, size_t frameEntries, size_t bezierCount) : Timeline(frameCount, frameEntries) {
_curves.setSize(frameCount + bezierCount * BEZIER_SIZE, 0);
_curves[frameCount - 1] = STEPPED;
}
CurveTimeline::~CurveTimeline() {
}
void CurveTimeline::setLinear(size_t frame) {
_curves[frame] = LINEAR;
}
void CurveTimeline::setStepped(size_t frame) {
_curves[frame] = STEPPED;
}
void CurveTimeline::setBezier(size_t bezier, size_t frame, float value, float time1, float value1, float cx1, float cy1, float cx2, float cy2,
float time2, float value2) {
size_t i = getFrameCount() + bezier * BEZIER_SIZE;
if (value == 0) _curves[frame] = BEZIER + i;
float tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = (value1 - cy1 * 2 + cy2) * 0.03;
float dddx = ((cx1 - cx2) * 3 - time1 + time2) * 0.006, dddy = ((cy1 - cy2) * 3 - value1 + value2) * 0.006;
float ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy;
float dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = (cy1 - value1) * 0.3 + tmpy + dddy * 0.16666667;
float x = time1 + dx, y = value1 + dy;
for (size_t n = i + BEZIER_SIZE; i < n; i += 2) {
_curves[i] = x;
_curves[i + 1] = y;
dx += ddx;
dy += ddy;
ddx += dddx;
ddy += dddy;
x += dx;
y += dy;
}
}
float CurveTimeline::getBezierValue(float time, size_t frameIndex, size_t valueOffset, size_t i) {
if (_curves[i] > time) {
float x = _frames[frameIndex], y = _frames[frameIndex + valueOffset];
return y + (time - x) / (_curves[i] - x) * (_curves[i + 1] - y);
}
size_t n = i + BEZIER_SIZE;
for (i += 2; i < n; i += 2) {
if (_curves[i] >= time) {
float x = _curves[i - 2], y = _curves[i - 1];
return y + (time - x) / (_curves[i] - x) * (_curves[i + 1] - y);
}
}
frameIndex += getFrameEntries();
float x = _curves[n - 2], y = _curves[n - 1];
return y + (time - x) / (_frames[frameIndex] - x) * (_frames[frameIndex + valueOffset] - y);
}
Array<float> &CurveTimeline::getCurves() {
return _curves;
}
RTTI_IMPL(CurveTimeline1, CurveTimeline)
CurveTimeline1::CurveTimeline1(size_t frameCount, size_t bezierCount) : CurveTimeline(frameCount, CurveTimeline1::ENTRIES, bezierCount) {
}
CurveTimeline1::~CurveTimeline1() {
}
void CurveTimeline1::setFrame(size_t frame, float time, float value) {
frame <<= 1;
_frames[frame] = time;
_frames[frame + CurveTimeline1::VALUE] = value;
}
float CurveTimeline1::getCurveValue(float time) {
int i = (int) _frames.size() - 2;
for (int ii = 2; ii <= i; ii += 2) {
if (_frames[ii] > time) {
i = ii - 2;
break;
}
}
int curveType = (int) _curves[i >> 1];
switch (curveType) {
case CurveTimeline::LINEAR: {
float before = _frames[i], value = _frames[i + CurveTimeline1::VALUE];
return value +
(time - before) / (_frames[i + CurveTimeline1::ENTRIES] - before) *
(_frames[i + CurveTimeline1::ENTRIES + CurveTimeline1::VALUE] - value);
}
case CurveTimeline::STEPPED:
return _frames[i + CurveTimeline1::VALUE];
}
return getBezierValue(time, i, CurveTimeline1::VALUE, curveType - CurveTimeline1::BEZIER);
}
float CurveTimeline1::getRelativeValue(float time, float alpha, bool fromSetup, bool add, float current, float setup) {
if (time < _frames[0]) return fromSetup ? setup : current;
float value = getCurveValue(time);
return fromSetup ? setup + value * alpha : current + (add ? value : value + setup - current) * alpha;
}
float CurveTimeline1::getAbsoluteValue(float time, float alpha, bool fromSetup, bool add, float current, float setup) {
if (time < _frames[0]) return fromSetup ? setup : current;
float value = getCurveValue(time);
return fromSetup ? setup + (value - setup) * alpha : current + (add ? value : value - current) * alpha;
}
float CurveTimeline1::getAbsoluteValue(float time, float alpha, bool fromSetup, bool add, float current, float setup, float value) {
if (time < _frames[0]) return fromSetup ? setup : current;
return fromSetup ? setup + (value - setup) * alpha : current + (add ? value : value - current) * alpha;
}
float CurveTimeline1::getScaleValue(float time, float alpha, bool fromSetup, bool add, bool out, float current, float setup) {
if (time < _frames[0]) return fromSetup ? setup : current;
float value = getCurveValue(time) * setup;
if (alpha == 1 && !add) return value;
float base = fromSetup ? setup : current;
if (add) return base + (value - setup) * alpha;
if (out) return base + (MathUtil::abs(value) * MathUtil::sign(base) - base) * alpha;
base = MathUtil::abs(base) * MathUtil::sign(value);
return base + (value - base) * alpha;
}

View File

@ -1,269 +0,0 @@
/******************************************************************************
* 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 <spine/DeformTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/VertexAttachment.h>
#include <spine/Animation.h>
#include <spine/Bone.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/SlotPose.h>
using namespace spine;
RTTI_IMPL(DeformTimeline, CurveTimeline)
DeformTimeline::DeformTimeline(size_t frameCount, size_t bezierCount, int slotIndex, VertexAttachment &attachment)
: SlotCurveTimeline(frameCount, 1, bezierCount, slotIndex), _attachment(&attachment) {
PropertyId ids[] = {((PropertyId) Property_Deform << 32) | ((slotIndex << 16 | attachment._id) & 0xffffffff)};
setPropertyIds(ids, 1);
_additive = true;
_vertices.ensureCapacity(frameCount);
for (size_t i = 0; i < frameCount; ++i) {
Array<float> vec;
_vertices.add(vec);
}
}
void DeformTimeline::_apply(Slot &slot, SlotPose &pose, float time, float alpha, bool fromSetup, bool add) {
SP_UNUSED(slot);
Attachment *slotAttachment = pose._attachment;
if (slotAttachment == NULL || !slotAttachment->getRTTI().instanceOf(VertexAttachment::rtti)) {
return;
}
VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slotAttachment);
if (vertexAttachment->getTimelineAttachment() != _attachment) {
return;
}
Array<float> &deformArray = pose._deform;
if (deformArray.size() == 0) fromSetup = true;
Array<Array<float>> &vertices = _vertices;
size_t vertexCount = vertices[0].size();
Array<float> &frames = _frames;
if (time < frames[0]) {
if (fromSetup) deformArray.clear();
return;
}
deformArray.setSize(vertexCount, 0);
Array<float> &deform = deformArray;
if (time >= frames[frames.size() - 1]) {// Time is after last frame.
Array<float> &lastVertices = vertices[frames.size() - 1];
if (alpha == 1) {
if (add && !fromSetup) {
if (vertexAttachment->getBones().size() == 0) {
// Unweighted vertex positions, no alpha.
Array<float> &setupVertices = vertexAttachment->getVertices();
for (size_t i = 0; i < vertexCount; i++) deform[i] += lastVertices[i] - setupVertices[i];
} else {
// Weighted deform offsets, no alpha.
for (size_t i = 0; i < vertexCount; i++) deform[i] += lastVertices[i];
}
} else {
// Vertex positions or deform offsets, no alpha.
memcpy(deform.buffer(), lastVertices.buffer(), vertexCount * sizeof(float));
}
} else if (fromSetup) {
if (vertexAttachment->getBones().size() == 0) {
// Unweighted vertex positions, with alpha.
Array<float> &setupVertices = vertexAttachment->getVertices();
for (size_t i = 0; i < vertexCount; i++) {
float setup = setupVertices[i];
deform[i] = setup + (lastVertices[i] - setup) * alpha;
}
} else {
// Weighted deform offsets, with alpha.
for (size_t i = 0; i < vertexCount; i++) deform[i] = lastVertices[i] * alpha;
}
} else if (add) {
if (vertexAttachment->getBones().size() == 0) {
// Unweighted vertex positions, with alpha.
Array<float> &setupVertices = vertexAttachment->getVertices();
for (size_t i = 0; i < vertexCount; i++) deform[i] += (lastVertices[i] - setupVertices[i]) * alpha;
} else {
// Weighted deform offsets, with alpha.
for (size_t i = 0; i < vertexCount; i++) deform[i] += lastVertices[i] * alpha;
}
} else {
// Vertex positions or deform offsets, with alpha.
for (size_t i = 0; i < vertexCount; i++) deform[i] += (lastVertices[i] - deform[i]) * alpha;
}
return;
}
// Interpolate between the previous frame and the current frame.
int frame = Animation::search(frames, time);
float percent = getCurvePercent(time, frame);
Array<float> &prevVertices = vertices[frame];
Array<float> &nextVertices = vertices[frame + 1];
if (alpha == 1) {
if (add && !fromSetup) {
if (vertexAttachment->getBones().size() == 0) {
// Unweighted vertex positions, no alpha.
Array<float> &setupVertices = vertexAttachment->getVertices();
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
deform[i] += prev + (nextVertices[i] - prev) * percent - setupVertices[i];
}
} else {
// Weighted deform offsets, no alpha.
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
deform[i] += prev + (nextVertices[i] - prev) * percent;
}
}
} else if (percent == 0) {
memcpy(deform.buffer(), prevVertices.buffer(), vertexCount * sizeof(float));
} else {
// Vertex positions or deform offsets, no alpha.
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
deform[i] = prev + (nextVertices[i] - prev) * percent;
}
}
} else if (fromSetup) {
if (vertexAttachment->getBones().size() == 0) {
// Unweighted vertex positions, with alpha.
Array<float> &setupVertices = vertexAttachment->getVertices();
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i], setup = setupVertices[i];
deform[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
}
} else {
// Weighted deform offsets, with alpha.
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
deform[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
}
}
} else if (add) {
if (vertexAttachment->getBones().size() == 0) {
// Unweighted vertex positions, with alpha.
Array<float> &setupVertices = vertexAttachment->getVertices();
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
deform[i] += (prev + (nextVertices[i] - prev) * percent - setupVertices[i]) * alpha;
}
} else {
// Weighted deform offsets, with alpha.
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
deform[i] += (prev + (nextVertices[i] - prev) * percent) * alpha;
}
}
} else {
// Vertex positions or deform offsets, with alpha.
for (size_t i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
deform[i] += (prev + (nextVertices[i] - prev) * percent - deform[i]) * alpha;
}
}
}
void DeformTimeline::setBezier(size_t bezier, size_t frame, float value, float time1, float value1, float cx1, float cy1, float cx2, float cy2,
float time2, float value2) {
SP_UNUSED(value1);
SP_UNUSED(value2);
Array<float> &curves = _curves;
size_t i = getFrameCount() + bezier * BEZIER_SIZE;
if (value == 0) curves[frame] = BEZIER + (float) i;
float tmpx = (time1 - cx1 * 2 + cx2) * 0.03f, tmpy = cy2 * 0.03f - cy1 * 0.06f;
float dddx = ((cx1 - cx2) * 3 - time1 + time2) * 0.006f, dddy = (cy1 - cy2 + 0.33333333f) * 0.018f;
float ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy;
float dx = (cx1 - time1) * 0.3f + tmpx + dddx * 0.16666667f, dy = cy1 * 0.3f + tmpy + dddy * 0.16666667f;
float x = time1 + dx, y = dy;
for (size_t n = i + BEZIER_SIZE; i < n; i += 2) {
curves[i] = x;
curves[i + 1] = y;
dx += ddx;
dy += ddy;
ddx += dddx;
ddy += dddy;
x += dx;
y += dy;
}
}
float DeformTimeline::getCurvePercent(float time, int frame) {
Array<float> &curves = _curves;
int i = (int) curves[frame];
switch (i) {
case LINEAR: {
float x = _frames[frame];
return (time - x) / (_frames[frame + getFrameEntries()] - x);
}
case STEPPED: {
return 0;
}
}
i -= BEZIER;
if (curves[i] > time) {
float x = _frames[frame];
return curves[i + 1] * (time - x) / (curves[i] - x);
}
int n = i + BEZIER_SIZE;
for (i += 2; i < n; i += 2) {
if (curves[i] >= time) {
float x = curves[i - 2], y = curves[i - 1];
return y + (time - x) / (curves[i] - x) * (curves[i + 1] - y);
}
}
float x = curves[n - 2], y = curves[n - 1];
return y + (1 - y) * (time - x) / (_frames[frame + getFrameEntries()] - x);
}
void DeformTimeline::setFrame(int frame, float time, Array<float> &vertices) {
_frames[frame] = time;
_vertices[frame].clear();
_vertices[frame].addAll(vertices);
}
Array<Array<float>> &DeformTimeline::getVertices() {
return _vertices;
}
VertexAttachment &DeformTimeline::getAttachment() {
return *_attachment;
}
void DeformTimeline::setAttachment(VertexAttachment &inValue) {
_attachment = &inValue;
}

View File

@ -1,116 +0,0 @@
/******************************************************************************
* 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 <spine/DrawOrderFolderTimeline.h>
#include <spine/Animation.h>
#include <spine/Event.h>
#include <spine/Property.h>
#include <spine/Skeleton.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(DrawOrderFolderTimeline, Timeline)
DrawOrderFolderTimeline::DrawOrderFolderTimeline(size_t frameCount, Array<int> &slots, size_t slotCount) : Timeline(frameCount, 1) {
Array<PropertyId> ids(slots.size());
for (size_t i = 0; i < slots.size(); ++i) ids.add(((PropertyId) Property_DrawOrderFolder << 32) | (PropertyId) slots[i]);
setPropertyIds(ids.buffer(), ids.size());
_slots.addAll(slots);
_drawOrders.ensureCapacity(frameCount);
_inFolder.setSize(slotCount, false);
for (size_t i = 0; i < _slots.size(); ++i) _inFolder[_slots[i]] = true;
_instant = true;
for (size_t i = 0; i < frameCount; ++i) {
Array<int> vec;
_drawOrders.add(vec);
}
}
void DrawOrderFolderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add,
bool out, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(alpha);
SP_UNUSED(add);
SP_UNUSED(appliedPose);
if (out || time < _frames[0]) {
if (fromSetup) setup(skeleton);
} else {
Array<int> &drawOrder = _drawOrders[Animation::search(_frames, time)];
if (drawOrder.size() == 0)
setup(skeleton);
else
apply(skeleton, drawOrder);
}
}
size_t DrawOrderFolderTimeline::getFrameCount() {
return _frames.size();
}
Array<int> &DrawOrderFolderTimeline::getSlots() {
return _slots;
}
Array<Array<int>> &DrawOrderFolderTimeline::getDrawOrders() {
return _drawOrders;
}
void DrawOrderFolderTimeline::setFrame(size_t frame, float time, Array<int> *drawOrder) {
_frames[frame] = time;
_drawOrders[frame].clear();
if (drawOrder != NULL) _drawOrders[frame].addAll(*drawOrder);
}
void DrawOrderFolderTimeline::setup(Skeleton &skeleton) {
Array<Slot *> &drawOrder = skeleton._drawOrder;
Array<Slot *> &allSlots = skeleton._slots;
for (size_t i = 0, found = 0, done = _slots.size();; ++i) {
if (_inFolder[drawOrder[i]->getData().getIndex()]) {
drawOrder[i] = allSlots[_slots[found]];
if (++found == done) break;
}
}
}
void DrawOrderFolderTimeline::apply(Skeleton &skeleton, Array<int> &drawOrderIndices) {
Array<Slot *> &drawOrder = skeleton._drawOrder;
Array<Slot *> &allSlots = skeleton._slots;
for (size_t i = 0, found = 0, done = _slots.size();; ++i) {
if (_inFolder[drawOrder[i]->getData().getIndex()]) {
drawOrder[i] = allSlots[_slots[drawOrderIndices[found]]];
if (++found == done) break;
}
}
}

View File

@ -1,105 +0,0 @@
/******************************************************************************
* 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 <spine/DrawOrderTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(DrawOrderTimeline, Timeline)
PropertyId DrawOrderTimeline::getPropertyId() {
return ((PropertyId) Property_DrawOrder << 32);
}
DrawOrderTimeline::DrawOrderTimeline(size_t frameCount) : Timeline(frameCount, 1) {
PropertyId ids[] = {getPropertyId()};
setPropertyIds(ids, 1);
_instant = true;
_drawOrders.ensureCapacity(frameCount);
for (size_t i = 0; i < frameCount; ++i) {
Array<int> vec;
_drawOrders.add(vec);
}
}
void DrawOrderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(appliedPose);
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(alpha);
SP_UNUSED(add);
Array<Slot *> &drawOrder = skeleton._drawOrder;
Array<Slot *> &slots = skeleton._slots;
if (out || time < _frames[0]) {
if (fromSetup) {
drawOrder.clear();
drawOrder.ensureCapacity(slots.size());
for (size_t i = 0, n = slots.size(); i < n; ++i) drawOrder.add(slots[i]);
}
return;
}
Array<int> &drawOrderToSetupIndex = _drawOrders[Animation::search(_frames, time)];
if (drawOrderToSetupIndex.size() == 0) {
drawOrder.clear();
drawOrder.ensureCapacity(slots.size());
for (size_t i = 0, n = slots.size(); i < n; ++i) drawOrder.add(slots[i]);
} else {
drawOrder.clear();
drawOrder.ensureCapacity(drawOrderToSetupIndex.size());
for (size_t i = 0, n = drawOrderToSetupIndex.size(); i < n; ++i) drawOrder.add(slots[drawOrderToSetupIndex[i]]);
}
}
void DrawOrderTimeline::setFrame(size_t frame, float time, Array<int> *drawOrder) {
_frames[frame] = time;
_drawOrders[frame].clear();
if (drawOrder != NULL) {
_drawOrders[frame].addAll(*drawOrder);
}
}
size_t DrawOrderTimeline::getFrameCount() {
return _frames.size();
}
Array<Array<int>> &DrawOrderTimeline::getDrawOrders() {
return _drawOrders;
}

View File

@ -1,88 +0,0 @@
/******************************************************************************
* 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 <spine/Event.h>
#include <spine/EventData.h>
using namespace spine;
Event::Event(float time, const EventData &data)
: _data(data), _time(time), _intValue(data.getInt()), _floatValue(data.getFloat()), _stringValue(data.getString()), _volume(data.getVolume()),
_balance(data.getBalance()) {
}
const EventData &Event::getData() {
return _data;
}
float Event::getTime() {
return _time;
}
int Event::getInt() {
return _intValue;
}
void Event::setInt(int inValue) {
_intValue = inValue;
}
float Event::getFloat() {
return _floatValue;
}
void Event::setFloat(float inValue) {
_floatValue = inValue;
}
const String &Event::getString() {
return _stringValue;
}
void Event::setString(const String &inValue) {
_stringValue = inValue;
}
float Event::getVolume() {
return _volume;
}
void Event::setVolume(float inValue) {
_volume = inValue;
}
float Event::getBalance() {
return _balance;
}
void Event::setBalance(float inValue) {
_balance = inValue;
}

View File

@ -1,92 +0,0 @@
/******************************************************************************
* 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 <spine/EventData.h>
#include <assert.h>
using namespace spine;
EventData::EventData(const String &name) : _name(name), _intValue(0), _floatValue(0), _stringValue(), _audioPath(), _volume(0), _balance(0) {
assert(_name.length() > 0);
}
/// The name of the event, which is unique within the skeleton.
const String &EventData::getName() const {
return _name;
}
int EventData::getInt() const {
return _intValue;
}
void EventData::setInt(int inValue) {
_intValue = inValue;
}
float EventData::getFloat() const {
return _floatValue;
}
void EventData::setFloat(float inValue) {
_floatValue = inValue;
}
const String &EventData::getString() const {
return _stringValue;
}
void EventData::setString(const String &inValue) {
this->_stringValue = inValue;
}
const String &EventData::getAudioPath() const {
return _audioPath;
}
void EventData::setAudioPath(const String &inValue) {
_audioPath = inValue;
}
float EventData::getVolume() const {
return _volume;
}
void EventData::setVolume(float inValue) {
_volume = inValue;
}
float EventData::getBalance() const {
return _balance;
}
void EventData::setBalance(float inValue) {
_balance = inValue;
}

View File

@ -1,106 +0,0 @@
/******************************************************************************
* 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 <spine/EventTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/ArrayUtils.h>
#include <spine/EventData.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <float.h>
using namespace spine;
RTTI_IMPL(EventTimeline, Timeline)
EventTimeline::EventTimeline(size_t frameCount) : Timeline(frameCount, 1) {
PropertyId ids[] = {((PropertyId) Property_Event << 32)};
setPropertyIds(ids, 1);
_events.setSize(frameCount, NULL);
_instant = true;
}
EventTimeline::~EventTimeline() {
ArrayUtils::deleteElements(_events);
}
void EventTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *pEvents, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(skeleton);
if (pEvents == NULL) return;
Array<Event *> &events = *pEvents;
size_t frameCount = _frames.size();
if (lastTime > time) {
// Apply after lastTime for looped animations.
apply(skeleton, lastTime, FLT_MAX, pEvents, 0, false, false, false, false);
lastTime = -1.0f;
} else if (lastTime >= _frames[frameCount - 1]) {
// Last time is after last frame.
return;
}
if (time < _frames[0]) return;// Time is before first frame.
int i;
if (lastTime < _frames[0]) {
i = 0;
} else {
i = Animation::search(_frames, lastTime) + 1;
float frameTime = _frames[i];
while (i > 0) {
// Fire multiple events with the same frame.
if (_frames[i - 1] != frameTime) break;
i--;
}
}
for (; (size_t) i < frameCount && time >= _frames[i]; i++) events.add(_events[i]);
}
void EventTimeline::setFrame(size_t frame, Event &event) {
_frames[frame] = event.getTime();
_events[frame] = &event;
}
size_t EventTimeline::getFrameCount() {
return _frames.size();
}
Array<Event *> &EventTimeline::getEvents() {
return _events;
}

View File

@ -1,124 +0,0 @@
/******************************************************************************
* 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 <spine/Extension.h>
#include <spine/SpineString.h>
#include <assert.h>
using namespace spine;
SpineExtension *SpineExtension::_instance = NULL;
void SpineExtension::setInstance(SpineExtension *inValue) {
assert(inValue);
_instance = inValue;
}
SpineExtension *SpineExtension::getInstance() {
if (!_instance) _instance = getDefaultExtension();
assert(_instance);
return _instance;
}
SpineExtension::~SpineExtension() {
}
SpineExtension::SpineExtension() {
}
DefaultSpineExtension::~DefaultSpineExtension() {
}
void *DefaultSpineExtension::_alloc(size_t size, const char *file, int line) {
SP_UNUSED(file);
SP_UNUSED(line);
if (size == 0) return 0;
void *ptr = ::malloc(size);
return ptr;
}
void *DefaultSpineExtension::_calloc(size_t size, const char *file, int line) {
SP_UNUSED(file);
SP_UNUSED(line);
if (size == 0) return 0;
void *ptr = ::malloc(size);
if (ptr) {
memset(ptr, 0, size);
}
return ptr;
}
void *DefaultSpineExtension::_realloc(void *ptr, size_t size, const char *file, int line) {
SP_UNUSED(file);
SP_UNUSED(line);
void *mem = NULL;
if (size == 0) return 0;
if (ptr == NULL)
mem = ::malloc(size);
else
mem = ::realloc(ptr, size);
return mem;
}
void DefaultSpineExtension::_free(void *mem, const char *file, int line) {
SP_UNUSED(file);
SP_UNUSED(line);
::free(mem);
}
char *DefaultSpineExtension::_readFile(const String &path, int *length) {
#if !defined(__EMSCRIPTEN__) && !defined(SPINE_NO_FILE_IO)
char *data;
FILE *file = fopen(path.buffer(), "rb");
if (!file) return 0;
fseek(file, 0, SEEK_END);
*length = (int) ftell(file);
fseek(file, 0, SEEK_SET);
data = SpineExtension::alloc<char>(*length, __FILE__, __LINE__);
fread(data, 1, *length, file);
fclose(file);
return data;
#else
return nullptr;
#endif
}
DefaultSpineExtension::DefaultSpineExtension() : SpineExtension() {
}

View File

@ -1,307 +0,0 @@
/******************************************************************************
* 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 <spine/IkConstraint.h>
#include <spine/Bone.h>
#include <spine/BonePose.h>
#include <spine/ConstraintData.h>
#include <spine/IkConstraintData.h>
#include <spine/Skeleton.h>
#include <spine/BoneData.h>
using namespace spine;
RTTI_IMPL(IkConstraint, Constraint)
IkConstraint::IkConstraint(IkConstraintData &data, Skeleton &skeleton) : IkConstraintBase(data), _target(skeleton._bones[data._target->getIndex()]) {
_bones.ensureCapacity(data._bones.size());
for (size_t i = 0; i < data._bones.size(); i++) {
BoneData *boneData = data._bones[i];
_bones.add(&skeleton._bones[boneData->getIndex()]->_constrained);
}
}
IkConstraint &IkConstraint::copy(Skeleton &skeleton) {
IkConstraint *copy = new (__FILE__, __LINE__) IkConstraint(_data, skeleton);
copy->_pose.set(_pose);
return *copy;
}
void IkConstraint::update(Skeleton &skeleton, Physics physics) {
IkConstraintPose &p = *_applied;
if (p._mix == 0) return;
BonePose &target = *_target->_applied;
switch (_bones.size()) {
case 1: {
apply(skeleton, *_bones[0], target._worldX, target._worldY, p._compress, p._stretch, _data._uniform, p._mix);
} break;
case 2: {
apply(skeleton, *_bones[0], *_bones[1], target._worldX, target._worldY, p._bendDirection, p._stretch, _data._uniform, p._softness,
p._mix);
} break;
}
}
void IkConstraint::sort(Skeleton &skeleton) {
skeleton.sortBone(_target);
Bone *parent = _bones[0]->_bone;
skeleton.sortBone(parent);
skeleton._updateCache.add(this);
parent->_sorted = false;
skeleton.sortReset(parent->_children);
skeleton.constrained(*parent);
if (_bones.size() > 1) skeleton.constrained(*_bones[1]->_bone);
}
Array<BonePose *> &IkConstraint::getBones() {
return _bones;
}
Bone &IkConstraint::getTarget() {
return *_target;
}
void IkConstraint::setTarget(Bone &target) {
_target = &target;
}
bool IkConstraint::isSourceActive() {
return _target->_active;
}
void IkConstraint::apply(Skeleton &skeleton, BonePose &bone, float targetX, float targetY, bool compress, bool stretch, bool uniform, float mix) {
bone.modifyLocal(skeleton);
BonePose &p = *bone._bone->_parent->_applied;
float pa = p._a, pb = p._b, pc = p._c, pd = p._d;
float rotationIK = -bone._shearX - bone._rotation, tx, ty;
switch (bone._inherit) {
case Inherit_OnlyTranslation:
tx = (targetX - bone._worldX) * MathUtil::sign(skeleton._scaleX);
ty = (targetY - bone._worldY) * MathUtil::sign(skeleton._scaleY);
break;
case Inherit_NoRotationOrReflection: {
float s = MathUtil::abs(pa * pd - pb * pc) / MathUtil::max(0.0001f, pa * pa + pc * pc);
float sa = pa / skeleton._scaleX;
float sc = pc / skeleton._scaleY;
pb = -sc * s * skeleton._scaleX;
pd = sa * s * skeleton._scaleY;
rotationIK += MathUtil::atan2Deg(sc, sa);
// Fall through.
}
default:
float x = targetX - p._worldX, y = targetY - p._worldY;
float d = pa * pd - pb * pc;
if (MathUtil::abs(d) <= 0.0001f) {
tx = 0;
ty = 0;
} else {
tx = (x * pd - y * pb) / d - bone._x;
ty = (y * pa - x * pc) / d - bone._y;
}
}
rotationIK += MathUtil::atan2Deg(ty, tx);
if (bone._scaleX < 0) rotationIK += 180;
if (rotationIK > 180)
rotationIK -= 360;
else if (rotationIK < -180)//
rotationIK += 360;
bone._rotation += rotationIK * mix;
if (compress || stretch) {
switch (bone._inherit) {
case Inherit_NoScale:
case Inherit_NoScaleOrReflection:
tx = targetX - bone._worldX;
ty = targetY - bone._worldY;
break;
default:
break;
}
float b = bone._bone->_data.getLength() * bone._scaleX;
if (b > 0.0001f) {
float dd = tx * tx + ty * ty;
if ((compress && dd < b * b) || (stretch && dd > b * b)) {
float s = (MathUtil::sqrt(dd) / b - 1) * mix + 1;
bone._scaleX *= s;
if (uniform) bone._scaleY *= s;
}
}
}
}
void IkConstraint::apply(Skeleton &skeleton, BonePose &parent, BonePose &child, float targetX, float targetY, int bendDir, bool stretch, bool uniform,
float softness, float mix) {
if (parent._inherit != Inherit_Normal || child._inherit != Inherit_Normal) return;
parent.modifyLocal(skeleton);
child.modifyLocal(skeleton);
float px = parent._x, py = parent._y, psx = parent._scaleX, psy = parent._scaleY, csx = child._scaleX;
int os1, os2, s2;
if (psx < 0) {
psx = -psx;
os1 = 180;
s2 = -1;
} else {
os1 = 0;
s2 = 1;
}
if (psy < 0) {
psy = -psy;
s2 = -s2;
}
if (csx < 0) {
csx = -csx;
os2 = 180;
} else
os2 = 0;
float cwx, cwy, a = parent._a, b = parent._b, c = parent._c, d = parent._d;
bool u = MathUtil::abs(psx - psy) <= 0.0001f;
if (!u || stretch) {
child._y = 0;
cwx = a * child._x + parent._worldX;
cwy = c * child._x + parent._worldY;
} else {
cwx = a * child._x + b * child._y + parent._worldX;
cwy = c * child._x + d * child._y + parent._worldY;
}
BonePose &pp = *parent._bone->_parent->_applied;
a = pp._a;
b = pp._b;
c = pp._c;
d = pp._d;
float id = a * d - b * c, x = cwx - pp._worldX, y = cwy - pp._worldY;
id = MathUtil::abs(id) <= 0.0001f ? 0 : 1 / id;
float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
float l1 = MathUtil::sqrt(dx * dx + dy * dy), l2 = child._bone->_data.getLength() * csx, a1, a2;
if (l1 < 0.0001f) {
apply(skeleton, parent, targetX, targetY, false, stretch, false, mix);
child._rotation = 0;
return;
}
x = targetX - pp._worldX;
y = targetY - pp._worldY;
float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
float dd = tx * tx + ty * ty;
if (softness != 0) {
softness *= psx * (csx + 1) * 0.5f;
float td = MathUtil::sqrt(dd), sd = td - l1 - l2 * psx + softness;
if (sd > 0) {
float p = MathUtil::min(1.0f, sd / (softness * 2)) - 1;
p = (sd - softness * (1 - p * p)) / td;
tx -= p * tx;
ty -= p * ty;
dd = tx * tx + ty * ty;
}
}
if (u) {
l2 *= psx;
float cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
if (cos < -1) {
cos = -1;
a2 = MathUtil::Pi * bendDir;
} else if (cos > 1) {
cos = 1;
a2 = 0;
if (stretch) {
a = (MathUtil::sqrt(dd) / (l1 + l2) - 1) * mix + 1;
parent._scaleX *= a;
if (uniform) parent._scaleY *= a;
}
} else
a2 = MathUtil::acos(cos) * bendDir;
a = l1 + l2 * cos;
b = l2 * MathUtil::sin(a2);
a1 = MathUtil::atan2(ty * a - tx * b, tx * a + ty * b);
} else {
a = psx * l2;
b = psy * l2;
float aa = a * a, bb = b * b, ta = MathUtil::atan2(ty, tx);
c = bb * l1 * l1 + aa * dd - aa * bb;
float c1 = -2 * bb * l1, c2 = bb - aa;
d = c1 * c1 - 4 * c2 * c;
if (d >= 0) {
float q = MathUtil::sqrt(d);
if (c1 < 0) q = -q;
q = -(c1 + q) * 0.5f;
float r0 = q / c2, r1 = c / q;
float r = MathUtil::abs(r0) < MathUtil::abs(r1) ? r0 : r1;
r0 = dd - r * r;
if (r0 >= 0) {
y = MathUtil::sqrt(r0) * bendDir;
a1 = ta - MathUtil::atan2(y, r);
a2 = MathUtil::atan2(y / psy, (r - l1) / psx);
goto outer_break;
}
}
float minAngle = MathUtil::Pi, minX = l1 - a, minDist = minX * minX, minY = 0;
float maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0;
c = -a * l1 / (aa - bb);
if (c >= -1 && c <= 1) {
c = MathUtil::acos(c);
x = a * MathUtil::cos(c) + l1;
y = b * MathUtil::sin(c);
d = x * x + y * y;
if (d < minDist) {
minAngle = c;
minDist = d;
minX = x;
minY = y;
}
if (d > maxDist) {
maxAngle = c;
maxDist = d;
maxX = x;
maxY = y;
}
}
if (dd <= (minDist + maxDist) * 0.5f) {
a1 = ta - MathUtil::atan2(minY * bendDir, minX);
a2 = minAngle * bendDir;
} else {
a1 = ta - MathUtil::atan2(maxY * bendDir, maxX);
a2 = maxAngle * bendDir;
}
}
outer_break:
float os = MathUtil::atan2(child._y, child._x) * s2;
a1 = (a1 - os) * MathUtil::Rad_Deg + os1 - parent._rotation;
if (a1 > 180)
a1 -= 360;
else if (a1 < -180)//
a1 += 360;
parent._rotation += a1 * mix;
a2 = ((a2 + os) * MathUtil::Rad_Deg - child._shearX) * s2 + os2 - child._rotation;
if (a2 > 180)
a2 -= 360;
else if (a2 < -180)//
a2 += 360;
child._rotation += a2 * mix;
}

View File

@ -1,64 +0,0 @@
/******************************************************************************
* 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 <spine/IkConstraintData.h>
#include <spine/IkConstraint.h>
#include <spine/BoneData.h>
#include <spine/Skeleton.h>
using namespace spine;
RTTI_IMPL(IkConstraintData, ConstraintData)
IkConstraintData::IkConstraintData(const String &name) : ConstraintDataGeneric<IkConstraint, IkConstraintPose>(name), _target(NULL), _uniform(false) {
}
Array<BoneData *> &IkConstraintData::getBones() {
return _bones;
}
BoneData &IkConstraintData::getTarget() {
return *_target;
}
void IkConstraintData::setTarget(BoneData &inValue) {
_target = &inValue;
}
bool IkConstraintData::getUniform() {
return _uniform;
}
void IkConstraintData::setUniform(bool uniform) {
_uniform = uniform;
}
Constraint &IkConstraintData::create(Skeleton &skeleton) {
return *(new (__FILE__, __LINE__) IkConstraint(*this, skeleton));
}

View File

@ -1,86 +0,0 @@
/******************************************************************************
* 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 <spine/IkConstraintPose.h>
using namespace spine;
IkConstraintPose::IkConstraintPose() : _bendDirection(0), _compress(false), _stretch(false), _mix(0), _softness(0) {
}
IkConstraintPose::~IkConstraintPose() {
}
void IkConstraintPose::set(IkConstraintPose &pose) {
_mix = pose._mix;
_softness = pose._softness;
_bendDirection = pose._bendDirection;
_compress = pose._compress;
_stretch = pose._stretch;
}
float IkConstraintPose::getMix() {
return _mix;
}
void IkConstraintPose::setMix(float mix) {
_mix = mix;
}
float IkConstraintPose::getSoftness() {
return _softness;
}
void IkConstraintPose::setSoftness(float softness) {
_softness = softness;
}
int IkConstraintPose::getBendDirection() {
return _bendDirection;
}
void IkConstraintPose::setBendDirection(int bendDirection) {
_bendDirection = bendDirection;
}
bool IkConstraintPose::getCompress() {
return _compress;
}
void IkConstraintPose::setCompress(bool compress) {
_compress = compress;
}
bool IkConstraintPose::getStretch() {
return _stretch;
}
void IkConstraintPose::setStretch(bool stretch) {
_stretch = stretch;
}

View File

@ -1,126 +0,0 @@
/******************************************************************************
* 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 <spine/IkConstraintTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/IkConstraint.h>
#include <spine/IkConstraintData.h>
#include <spine/IkConstraintPose.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL_MULTI(IkConstraintTimeline, CurveTimeline, ConstraintTimeline)
IkConstraintTimeline::IkConstraintTimeline(size_t frameCount, size_t bezierCount, int constraintIndex)
: CurveTimeline(frameCount, IkConstraintTimeline::ENTRIES, bezierCount), ConstraintTimeline(), _constraintIndex(constraintIndex) {
PropertyId ids[] = {((PropertyId) Property_IkConstraint << 32) | constraintIndex};
setPropertyIds(ids, 1);
}
IkConstraintTimeline::~IkConstraintTimeline() {
}
void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add,
bool out, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(add);
IkConstraint *constraint = (IkConstraint *) skeleton._constraints[_constraintIndex];
if (!constraint->isActive()) return;
IkConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
if (time < _frames[0]) {
if (fromSetup) {
IkConstraintPose &setup = constraint->_data._setup;
pose._mix = setup._mix;
pose._softness = setup._softness;
pose._bendDirection = setup._bendDirection;
pose._compress = setup._compress;
pose._stretch = setup._stretch;
}
return;
}
float mix = 0, softness = 0;
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i / ENTRIES];
switch (curveType) {
case LINEAR: {
float before = _frames[i];
mix = _frames[i + MIX];
softness = _frames[i + SOFTNESS];
float t = (time - before) / (_frames[i + ENTRIES] - before);
mix += (_frames[i + ENTRIES + MIX] - mix) * t;
softness += (_frames[i + ENTRIES + SOFTNESS] - softness) * t;
break;
}
case STEPPED: {
mix = _frames[i + MIX];
softness = _frames[i + SOFTNESS];
break;
}
default: {
mix = getBezierValue(time, i, MIX, curveType - BEZIER);
softness = getBezierValue(time, i, SOFTNESS, curveType + BEZIER_SIZE - BEZIER);
}
}
IkConstraintPose &base = fromSetup ? constraint->_data._setup : pose;
pose._mix = base._mix + (mix - base._mix) * alpha;
pose._softness = base._softness + (softness - base._softness) * alpha;
if (out) {
if (fromSetup) {
pose._bendDirection = base._bendDirection;
pose._compress = base._compress;
pose._stretch = base._stretch;
}
} else {
pose._bendDirection = (int) _frames[i + BEND_DIRECTION];
pose._compress = _frames[i + COMPRESS] != 0;
pose._stretch = _frames[i + STRETCH] != 0;
}
}
void IkConstraintTimeline::setFrame(int frame, float time, float mix, float softness, int bendDirection, bool compress, bool stretch) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + MIX] = mix;
_frames[frame + SOFTNESS] = softness;
_frames[frame + BEND_DIRECTION] = (float) bendDirection;
_frames[frame + COMPRESS] = compress ? 1 : 0;
_frames[frame + STRETCH] = stretch ? 1 : 0;
}

View File

@ -1,81 +0,0 @@
/******************************************************************************
* 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 <spine/InheritTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/BoneLocal.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL_MULTI(InheritTimeline, Timeline, BoneTimeline)
InheritTimeline::InheritTimeline(size_t frameCount, int boneIndex) : Timeline(frameCount, ENTRIES), BoneTimeline(boneIndex) {
PropertyId ids[] = {((PropertyId) Property_Inherit << 32) | boneIndex};
setPropertyIds(ids, 1);
_instant = true;
}
InheritTimeline::~InheritTimeline() {
}
void InheritTimeline::setFrame(int frame, float time, Inherit inherit) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + INHERIT] = (float) inherit;
}
void InheritTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(alpha);
SP_UNUSED(add);
Bone *bone = skeleton._bones[_boneIndex];
if (!bone->isActive()) return;
BoneLocal &pose = appliedPose ? *bone->_applied : bone->_pose;
if (out) {
if (fromSetup) pose._inherit = bone->_data._setup._inherit;
} else {
if (time < _frames[0]) {
if (fromSetup) pose._inherit = bone->_data._setup._inherit;
} else {
int idx = Animation::search(_frames, time, ENTRIES) + INHERIT;
pose._inherit = static_cast<Inherit>((int) _frames[idx]);
}
}
}

View File

@ -1,555 +0,0 @@
/*
Copyright (c) 2009, Dave Gamble
Copyright (c) 2013, Esoteric Software
Permission is hereby granted, dispose of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Json */
/* JSON parser in CPP, from json.c in the spine-c runtime */
#ifndef _DEFAULT_SOURCE
/* Bring strings.h definitions into string.h, where appropriate */
#define _DEFAULT_SOURCE
#endif
#ifndef _BSD_SOURCE
/* Bring strings.h definitions into string.h, where appropriate */
#define _BSD_SOURCE
#endif
#include <spine/Json.h>
#include <spine/Extension.h>
#include <spine/SpineString.h>
#include <spine/Array.h>
#include <assert.h>
#include <math.h>
using namespace spine;
const int Json::JSON_FALSE = 0;
const int Json::JSON_TRUE = 1;
const int Json::JSON_NULL = 2;
const int Json::JSON_NUMBER = 3;
const int Json::JSON_STRING = 4;
const int Json::JSON_ARRAY = 5;
const int Json::JSON_OBJECT = 6;
const char *Json::_error = NULL;
Json *Json::getItem(Json *object, const char *string) {
Json *c = object->_child;
while (c && json_strcasecmp(c->_name, string)) {
c = c->_next;
}
return c;
}
Json *Json::getItem(Json *object, int childIndex) {
Json *current = object->_child;
while (current != NULL && childIndex > 0) {
childIndex--;
current = current->_next;
}
return current;
}
const char *Json::getString(Json *object, const char *name, const char *defaultValue) {
object = getItem(object, name);
if (object) {
return object->_valueString;
}
return defaultValue;
}
float Json::getFloat(Json *value, const char *name, float defaultValue) {
value = getItem(value, name);
return value ? value->_valueFloat : defaultValue;
}
int Json::getInt(Json *value, const char *name, int defaultValue) {
value = getItem(value, name);
return value ? value->_valueInt : defaultValue;
}
bool Json::getBoolean(Json *value, const char *name, bool defaultValue) {
value = getItem(value, name);
if (value) {
if (value->_valueString) return strcmp(value->_valueString, "true") == 0;
if (value->_type == JSON_NULL) return false;
if (value->_type == JSON_NUMBER) return value->_valueFloat != 0;
if (value->_type == JSON_FALSE) return false;
if (value->_type == JSON_TRUE) return true;
return defaultValue;
} else {
return defaultValue;
}
}
const char *Json::getError() {
return _error;
}
Json::Json(const char *value)
: _next(NULL),
#if SPINE_JSON_HAVE_PREV
_prev(NULL),
#endif
_child(NULL), _type(0), _size(0), _valueString(NULL), _valueInt(0), _valueFloat(0), _name(NULL) {
if (value) {
value = parseValue(this, skip(value));
assert(value);
}
}
Json::~Json() {
Json *curr = NULL;
Json *next = _child;
do {
curr = next;
if (curr) {
next = curr->_next;
}
delete curr;
} while (next);
if (_valueString) {
SpineExtension::free(_valueString, __FILE__, __LINE__);
}
if (_name) {
SpineExtension::free(_name, __FILE__, __LINE__);
}
}
const char *Json::skip(const char *inValue) {
if (!inValue) {
/* must propagate NULL since it's often called in skip(f(...)) form */
return NULL;
}
while (*inValue && (unsigned char) *inValue <= 32) {
inValue++;
}
return inValue;
}
const char *Json::parseValue(Json *item, const char *value) {
/* Referenced by constructor, parseArray(), and parseObject(). */
/* Always called with the result of skip(). */
#ifdef SPINE_JSON_DEBUG /* Checked at entry to graph, constructor, and after every parse call. */
if (!value) {
/* Fail on null. */
return NULL;
}
#endif
switch (*value) {
case 'n': {
if (!strncmp(value + 1, "ull", 3)) {
item->_type = JSON_NULL;
return value + 4;
}
break;
}
case 'f': {
if (!strncmp(value + 1, "alse", 4)) {
item->_type = JSON_FALSE;
/* calloc prevents us needing item->_type = JSON_FALSE or valueInt = 0 here */
return value + 5;
}
break;
}
case 't': {
if (!strncmp(value + 1, "rue", 3)) {
item->_type = JSON_TRUE;
item->_valueInt = 1;
return value + 4;
}
break;
}
case '\"':
return parseString(item, value);
case '[':
return parseArray(item, value);
case '{':
return parseObject(item, value);
case '-': /* fallthrough */
case '0': /* fallthrough */
case '1': /* fallthrough */
case '2': /* fallthrough */
case '3': /* fallthrough */
case '4': /* fallthrough */
case '5': /* fallthrough */
case '6': /* fallthrough */
case '7': /* fallthrough */
case '8': /* fallthrough */
case '9':
return parseNumber(item, value);
default:
break;
}
_error = value;
return NULL; /* failure. */
}
static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
const char *Json::parseString(Json *item, const char *str) {
const char *ptr = str + 1;
char *ptr2;
char *out;
int len = 0;
unsigned uc, uc2;
if (*str != '\"') {
/* TODO: don't need this check when called from parseValue, but do need from parseObject */
_error = str;
return 0;
} /* not a string! */
while (*ptr != '\"' && *ptr && ++len) {
if (*ptr++ == '\\') {
ptr++; /* Skip escaped quotes. */
}
}
out = SpineExtension::alloc<char>(len + 1, __FILE__, __LINE__); /* The length needed for the string, roughly. */
if (!out) {
return 0;
}
ptr = str + 1;
ptr2 = out;
while (*ptr != '\"' && *ptr) {
if (*ptr != '\\') {
*ptr2++ = *ptr++;
} else {
ptr++;
switch (*ptr) {
case 'b':
*ptr2++ = '\b';
break;
case 'f':
*ptr2++ = '\f';
break;
case 'n':
*ptr2++ = '\n';
break;
case 'r':
*ptr2++ = '\r';
break;
case 't':
*ptr2++ = '\t';
break;
case 'u': {
/* transcode utf16 to utf8. */
sscanf(ptr + 1, "%4x", &uc);
ptr += 4; /* get the unicode char. */
if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) {
break; /* check for invalid. */
}
/* TODO provide an option to ignore surrogates, use unicode replacement character? */
if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */ {
if (ptr[1] != '\\' || ptr[2] != 'u') {
break; /* missing second-half of surrogate. */
}
sscanf(ptr + 3, "%4x", &uc2);
ptr += 6;
if (uc2 < 0xDC00 || uc2 > 0xDFFF) {
break; /* invalid second-half of surrogate. */
}
uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
}
len = 4;
if (uc < 0x80) {
len = 1;
} else if (uc < 0x800) {
len = 2;
} else if (uc < 0x10000) {
len = 3;
}
ptr2 += len;
switch (len) {
case 4:
*--ptr2 = ((uc | 0x80) & 0xBF);
uc >>= 6;
/* fallthrough */
case 3:
*--ptr2 = ((uc | 0x80) & 0xBF);
uc >>= 6;
/* fallthrough */
case 2:
*--ptr2 = ((uc | 0x80) & 0xBF);
uc >>= 6;
/* fallthrough */
case 1:
*--ptr2 = (uc | firstByteMark[len]);
}
ptr2 += len;
break;
}
default:
*ptr2++ = *ptr;
break;
}
ptr++;
}
}
*ptr2 = 0;
if (*ptr == '\"') {
ptr++; /* TODO error handling if not \" or \0 ? */
}
item->_valueString = out;
item->_type = JSON_STRING;
return ptr;
}
const char *Json::parseNumber(Json *item, const char *num) {
double result = 0.0;
int negative = 0;
char *ptr = (char *) num;
if (*ptr == '-') {
negative = -1;
++ptr;
}
while (*ptr >= '0' && *ptr <= '9') {
result = result * 10.0 + (*ptr - '0');
++ptr;
}
if (*ptr == '.') {
double fraction = 0.0;
int n = 0;
++ptr;
while (*ptr >= '0' && *ptr <= '9') {
fraction = (fraction * 10.0) + (*ptr - '0');
++ptr;
++n;
}
result += fraction / pow(10.0, n);
}
if (negative) {
result = -result;
}
if (*ptr == 'e' || *ptr == 'E') {
double exponent = 0;
int expNegative = 0;
++ptr;
if (*ptr == '-') {
expNegative = -1;
++ptr;
} else if (*ptr == '+') {
++ptr;
}
while (*ptr >= '0' && *ptr <= '9') {
exponent = (exponent * 10.0) + (*ptr - '0');
++ptr;
}
if (expNegative) {
result = result / pow(10, exponent);
} else {
result = result * pow(10, exponent);
}
}
if (ptr != num) {
/* Parse success, number found. */
item->_valueFloat = (float) result;
item->_valueInt = (int) result;
item->_type = JSON_NUMBER;
return ptr;
} else {
/* Parse failure, _error is set. */
_error = num;
return NULL;
}
}
const char *Json::parseArray(Json *item, const char *value) {
Json *child;
#ifdef SPINE_JSON_DEBUG /* unnecessary, only callsite (parse_value) verifies this */
if (*value != '[') {
ep = value;
return 0;
} /* not an array! */
#endif
item->_type = JSON_ARRAY;
value = skip(value + 1);
if (*value == ']') {
return value + 1; /* empty array. */
}
item->_child = child = new (__FILE__, __LINE__) Json(NULL);
if (!item->_child) {
return NULL; /* memory fail */
}
value = skip(parseValue(child, skip(value))); /* skip any spacing, get the value. */
if (!value) {
return NULL;
}
item->_size = 1;
while (*value == ',') {
Json *new_item = new (__FILE__, __LINE__) Json(NULL);
if (!new_item) {
return NULL; /* memory fail */
}
child->_next = new_item;
#if SPINE_JSON_HAVE_PREV
new_item->prev = child;
#endif
child = new_item;
value = skip(parseValue(child, skip(value + 1)));
if (!value) {
return NULL; /* parse fail */
}
item->_size++;
}
if (*value == ']') {
return value + 1; /* end of array */
}
_error = value;
return NULL; /* malformed. */
}
/* Build an object from the text. */
const char *Json::parseObject(Json *item, const char *value) {
Json *child;
#ifdef SPINE_JSON_DEBUG /* unnecessary, only callsite (parse_value) verifies this */
if (*value != '{') {
ep = value;
return 0;
} /* not an object! */
#endif
item->_type = JSON_OBJECT;
value = skip(value + 1);
if (*value == '}') {
return value + 1; /* empty array. */
}
item->_child = child = new (__FILE__, __LINE__) Json(NULL);
if (!item->_child) {
return NULL;
}
value = skip(parseString(child, skip(value)));
if (!value) {
return NULL;
}
child->_name = child->_valueString;
child->_valueString = 0;
if (*value != ':') {
_error = value;
return NULL;
} /* fail! */
value = skip(parseValue(child, skip(value + 1))); /* skip any spacing, get the value. */
if (!value) {
return NULL;
}
item->_size = 1;
while (*value == ',') {
Json *new_item = new (__FILE__, __LINE__) Json(NULL);
if (!new_item) {
return NULL; /* memory fail */
}
child->_next = new_item;
#if SPINE_JSON_HAVE_PREV
new_item->prev = child;
#endif
child = new_item;
value = skip(parseString(child, skip(value + 1)));
if (!value) {
return NULL;
}
child->_name = child->_valueString;
child->_valueString = 0;
if (*value != ':') {
_error = value;
return NULL;
} /* fail! */
value = skip(parseValue(child, skip(value + 1))); /* skip any spacing, get the value. */
if (!value) {
return NULL;
}
item->_size++;
}
if (*value == '}') {
return value + 1; /* end of array */
}
_error = value;
return NULL; /* malformed. */
}
int Json::json_strcasecmp(const char *s1, const char *s2) {
/* TODO we may be able to elide these NULL checks if we can prove
* the graph and input (only callsite is Json_getItem) should not have NULLs
*/
if (s1 && s2) {
#if defined(_WIN32)
return _stricmp(s1, s2);
#else
return strcasecmp(s1, s2);
#endif
} else {
if (s1 < s2) {
return -1; /* s1 is null, s2 is not */
} else if (s1 == s2) {
return 0; /* both are null */
} else {
return 1; /* s2 is nul s1 is not */
}
}
}

View File

@ -1,42 +0,0 @@
/******************************************************************************
* 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 <spine/LinkedMesh.h>
#include <spine/MeshAttachment.h>
using namespace spine;
LinkedMesh::LinkedMesh(MeshAttachment &mesh, const int skinIndex, size_t slotIndex, const String &parent, bool inheritTimelines)
: _mesh(&mesh), _skinIndex(skinIndex), _skin(""), _slotIndex(slotIndex), _parent(parent), _inheritTimelines(inheritTimelines) {
}
LinkedMesh::LinkedMesh(MeshAttachment &mesh, const String &skin, size_t slotIndex, const String &parent, bool inheritTimelines)
: _mesh(&mesh), _skinIndex(-1), _skin(skin), _slotIndex(slotIndex), _parent(parent), _inheritTimelines(inheritTimelines) {
}

View File

@ -1,131 +0,0 @@
/******************************************************************************
* 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 <spine/MathUtil.h>
#include <math.h>
#include <stdlib.h>
#include <cmath>
// Required for division by 0 in _isNaN on MSVC
#ifdef _MSC_VER
#pragma warning(disable : 4723)
#endif
using namespace spine;
const float MathUtil::Pi = 3.1415926535897932385f;
const float MathUtil::Pi_2 = 3.1415926535897932385f * 2;
const float MathUtil::InvPi_2 = 1 / MathUtil::Pi_2;
const float MathUtil::Deg_Rad = (3.1415926535897932385f / 180.0f);
const float MathUtil::Rad_Deg = (180.0f / 3.1415926535897932385f);
float MathUtil::abs(float v) {
return ((v) < 0 ? -(v) : (v));
}
float MathUtil::sign(float v) {
return ((v) < 0 ? -1.0f : (v) > 0 ? 1.0f : 0.0f);
}
float MathUtil::clamp(float x, float min, float max) {
return ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)));
}
float MathUtil::fmod(float a, float b) {
return (float) ::fmod(a, b);
}
/// Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323
/// degrees), largest error of 0.00488 radians (0.2796 degrees).
float MathUtil::atan2(float y, float x) {
return (float) ::atan2(y, x);
}
float MathUtil::atan2Deg(float y, float x) {
return MathUtil::atan2(y, x) * MathUtil::Rad_Deg;
}
/// Returns the cosine in radians from a lookup table.
float MathUtil::cos(float radians) {
return (float) ::cos(radians);
}
/// Returns the sine in radians from a lookup table.
float MathUtil::sin(float radians) {
return (float) ::sin(radians);
}
float MathUtil::sqrt(float v) {
return (float) ::sqrt(v);
}
float MathUtil::acos(float v) {
return (float) ::acos(v);
}
/// Returns the sine in radians from a lookup table.
float MathUtil::sinDeg(float degrees) {
return (float) ::sin(degrees * MathUtil::Deg_Rad);
}
/// Returns the cosine in radians from a lookup table.
float MathUtil::cosDeg(float degrees) {
return (float) ::cos(degrees * MathUtil::Deg_Rad);
}
bool MathUtil::isNan(float v) {
return std::isnan(v);
}
float MathUtil::quietNan() {
return std::nan("");
}
float MathUtil::random() {
return ::rand() / (float) RAND_MAX;
}
float MathUtil::randomTriangular(float min, float max) {
return randomTriangular(min, max, (min + max) * 0.5f);
}
float MathUtil::randomTriangular(float min, float max, float mode) {
float u = random();
float d = max - min;
if (u <= (mode - min) / d) return min + sqrt(u * d * (mode - min));
return max - sqrt((1 - u) * d * (max - mode));
}
float MathUtil::pow(float a, float b) {
return (float) ::pow(a, b);
}
float MathUtil::ceil(float v) {
return ::ceil(v);
}

View File

@ -1,230 +0,0 @@
/******************************************************************************
* 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 <spine/MeshAttachment.h>
#include <spine/Atlas.h>
#include <assert.h>
using namespace spine;
RTTI_IMPL(MeshAttachment, VertexAttachment)
MeshAttachment::MeshAttachment(const String &name, Sequence *sequence)
: VertexAttachment(name), _sequence(sequence), _regionUVs(), _triangles(), _hullLength(0), _path(), _color(1, 1, 1, 1), _parentMesh(NULL),
_edges(), _width(0), _height(0) {
assert(sequence);
}
MeshAttachment::~MeshAttachment() {
delete _sequence;
}
void MeshAttachment::computeWorldVertices(Skeleton &skeleton, Slot &slot, size_t start, size_t count, float *worldVertices, size_t offset,
size_t stride) {
VertexAttachment::computeWorldVertices(skeleton, slot, start, count, worldVertices, offset, stride);
}
Array<float> &MeshAttachment::getRegionUVs() {
return _regionUVs;
}
void MeshAttachment::setRegionUVs(Array<float> &inValue) {
_regionUVs.clearAndAddAll(inValue);
}
Array<unsigned short> &MeshAttachment::getTriangles() {
return _triangles;
}
void MeshAttachment::setTriangles(Array<unsigned short> &inValue) {
_triangles.clearAndAddAll(inValue);
}
int MeshAttachment::getHullLength() {
return _hullLength;
}
void MeshAttachment::setHullLength(int inValue) {
_hullLength = inValue;
}
Sequence &MeshAttachment::getSequence() {
return *_sequence;
}
void MeshAttachment::updateSequence() {
_sequence->update(*this);
}
const String &MeshAttachment::getPath() {
return _path;
}
void MeshAttachment::setPath(const String &inValue) {
_path = inValue;
}
Color &MeshAttachment::getColor() {
return _color;
}
MeshAttachment *MeshAttachment::getParentMesh() {
return _parentMesh;
}
void MeshAttachment::setParentMesh(MeshAttachment *inValue) {
_parentMesh = inValue;
if (inValue != NULL) {
_bones.clearAndAddAll(inValue->_bones);
_vertices.clearAndAddAll(inValue->_vertices);
_regionUVs.clearAndAddAll(inValue->_regionUVs);
_triangles.clearAndAddAll(inValue->_triangles);
_hullLength = inValue->_hullLength;
_worldVerticesLength = inValue->_worldVerticesLength;
_edges.clearAndAddAll(inValue->_edges);
_width = inValue->_width;
_height = inValue->_height;
}
}
Array<unsigned short> &MeshAttachment::getEdges() {
return _edges;
}
void MeshAttachment::setEdges(Array<unsigned short> &inValue) {
_edges.clearAndAddAll(inValue);
}
float MeshAttachment::getWidth() {
return _width;
}
void MeshAttachment::setWidth(float inValue) {
_width = inValue;
}
float MeshAttachment::getHeight() {
return _height;
}
void MeshAttachment::setHeight(float inValue) {
_height = inValue;
}
Attachment &MeshAttachment::copy() {
if (_parentMesh) return newLinkedMesh();
MeshAttachment *copy = new (__FILE__, __LINE__) MeshAttachment(getName(), new (__FILE__, __LINE__) Sequence(*_sequence));
copy->_path = _path;
copy->_color.set(_color);
copyTo(*copy);
copy->_regionUVs.clearAndAddAll(_regionUVs);
copy->_triangles.clearAndAddAll(_triangles);
copy->_hullLength = _hullLength;
copy->_edges.clearAndAddAll(_edges);
copy->_width = _width;
copy->_height = _height;
return *copy;
}
MeshAttachment &MeshAttachment::newLinkedMesh() {
MeshAttachment *copy = new (__FILE__, __LINE__) MeshAttachment(getName(), new (__FILE__, __LINE__) Sequence(*_sequence));
copy->setTimelineAttachment(getTimelineAttachment());
copy->_path = _path;
copy->_color.set(_color);
copy->setParentMesh(_parentMesh != NULL ? _parentMesh : this);
copy->updateSequence();
return *copy;
}
void MeshAttachment::computeUVs(TextureRegion *region, Array<float> &regionUVs, Array<float> &uvs) {
int n = (int) uvs.size();
float u, v, width, height;
if (region != NULL && region->getRTTI().instanceOf(AtlasRegion::rtti)) {
AtlasRegion *r = static_cast<AtlasRegion *>(region);
u = r->_u;
v = r->_v;
float textureWidth = r->getPage()->width;
float textureHeight = r->getPage()->height;
switch (r->_degrees) {
case 90: {
u -= (r->_originalHeight - r->_offsetY - r->_packedWidth) / textureWidth;
v -= (r->_originalWidth - r->_offsetX - r->_packedHeight) / textureHeight;
width = r->_originalHeight / textureWidth;
height = r->_originalWidth / textureHeight;
for (int i = 0; i < n; i += 2) {
uvs[i] = u + regionUVs[i + 1] * width;
uvs[i + 1] = v + (1 - regionUVs[i]) * height;
}
return;
}
case 180: {
u -= (r->_originalWidth - r->_offsetX - r->_packedWidth) / textureWidth;
v -= r->_offsetY / textureHeight;
width = r->_originalWidth / textureWidth;
height = r->_originalHeight / textureHeight;
for (int i = 0; i < n; i += 2) {
uvs[i] = u + (1 - regionUVs[i]) * width;
uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height;
}
return;
}
case 270: {
u -= r->_offsetY / textureWidth;
v -= r->_offsetX / textureHeight;
width = r->_originalHeight / textureWidth;
height = r->_originalWidth / textureHeight;
for (int i = 0; i < n; i += 2) {
uvs[i] = u + (1 - regionUVs[i + 1]) * width;
uvs[i + 1] = v + regionUVs[i] * height;
}
return;
}
default: {
u -= r->_offsetX / textureWidth;
v -= (r->_originalHeight - r->_offsetY - r->_packedHeight) / textureHeight;
width = r->_originalWidth / textureWidth;
height = r->_originalHeight / textureHeight;
}
}
} else if (region == NULL) {
u = v = 0;
width = height = 1;
} else {
u = region->_u;
v = region->_v;
width = region->_u2 - u;
height = region->_v2 - v;
}
for (int i = 0; i < n; i += 2) {
uvs[i] = u + regionUVs[i] * width;
uvs[i + 1] = v + regionUVs[i + 1] * height;
}
}

View File

@ -1,74 +0,0 @@
/******************************************************************************
* 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 <spine/PathAttachment.h>
using namespace spine;
RTTI_IMPL(PathAttachment, VertexAttachment)
PathAttachment::PathAttachment(const String &name) : VertexAttachment(name), _closed(false), _constantSpeed(false), _color() {
}
Array<float> &PathAttachment::getLengths() {
return _lengths;
}
void PathAttachment::setLengths(Array<float> &inValue) {
_lengths.clearAndAddAll(inValue);
}
bool PathAttachment::getClosed() {
return _closed;
}
void PathAttachment::setClosed(bool inValue) {
_closed = inValue;
}
bool PathAttachment::getConstantSpeed() {
return _constantSpeed;
}
void PathAttachment::setConstantSpeed(bool inValue) {
_constantSpeed = inValue;
}
Color &PathAttachment::getColor() {
return _color;
}
Attachment &PathAttachment::copy() {
PathAttachment *copy = new (__FILE__, __LINE__) PathAttachment(getName());
copyTo(*copy);
copy->_lengths.clearAndAddAll(_lengths);
copy->_closed = _closed;
copy->_constantSpeed = _constantSpeed;
return *copy;
}

View File

@ -1,552 +0,0 @@
/******************************************************************************
* 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 <spine/PathConstraint.h>
#include <spine/Bone.h>
#include <spine/BonePose.h>
#include <spine/PathAttachment.h>
#include <spine/PathConstraintData.h>
#include <spine/PathConstraintPose.h>
#include <spine/Skeleton.h>
#include <spine/Slot.h>
#include <spine/MathUtil.h>
#include <spine/Skin.h>
#include <spine/BoneData.h>
#include <spine/SlotData.h>
#include <spine/SkeletonData.h>
using namespace spine;
RTTI_IMPL(PathConstraint, Constraint)
const float PathConstraint::epsilon = 0.00001f;
const int PathConstraint::NONE = -1;
const int PathConstraint::BEFORE = -2;
const int PathConstraint::AFTER = -3;
PathConstraint::PathConstraint(PathConstraintData &data, Skeleton &skeleton) : PathConstraintBase(data) {
_bones.ensureCapacity(data.getBones().size());
for (size_t i = 0; i < data.getBones().size(); i++) {
BoneData *boneData = data.getBones()[i];
_bones.add(&skeleton._bones[boneData->getIndex()]->_constrained);
}
_slot = skeleton._slots[data._slot->_index];
_segments.setSize(10, 0);
}
PathConstraint &PathConstraint::copy(Skeleton &skeleton) {
PathConstraint *copy = new (__FILE__, __LINE__) PathConstraint(_data, skeleton);
copy->_pose.set(_pose);
return *copy;
}
void PathConstraint::update(Skeleton &skeleton, Physics physics) {
Attachment *baseAttachment = _slot->_applied->_attachment;
if (baseAttachment == NULL || !baseAttachment->getRTTI().instanceOf(PathAttachment::rtti)) {
return;
}
PathAttachment *pathAttachment = static_cast<PathAttachment *>(baseAttachment);
PathConstraintPose &p = *_applied;
float mixRotate = p._mixRotate, mixX = p._mixX, mixY = p._mixY;
if (mixRotate == 0 && mixX == 0 && mixY == 0) return;
PathConstraintData &data = _data;
bool tangents = data._rotateMode == RotateMode_Tangent, scale = data._rotateMode == RotateMode_ChainScale;
size_t boneCount = _bones.size();
size_t spacesCount = tangents ? boneCount : boneCount + 1;
BonePose **bones = _bones.buffer();
_spaces.setSize(spacesCount, 0);
float *spaces = _spaces.buffer();
float *lengths = NULL;
if (scale) {
_lengths.setSize(boneCount, 0);
lengths = _lengths.buffer();
}
float spacing = p._spacing;
switch (data._spacingMode) {
case SpacingMode_Percent: {
if (scale) {
for (size_t i = 0, n = spacesCount - 1; i < n; i++) {
BonePose *bone = bones[i];
float setupLength = bone->_bone->getData().getLength();
float x = setupLength * bone->_a;
float y = setupLength * bone->_c;
lengths[i] = MathUtil::sqrt(x * x + y * y);
}
}
for (size_t i = 1; i < spacesCount; i++) {
spaces[i] = spacing;
}
break;
}
case SpacingMode_Proportional: {
float sum = 0;
for (size_t i = 0, n = spacesCount - 1; i < n;) {
BonePose *bone = bones[i];
float setupLength = bone->_bone->getData().getLength();
if (setupLength < epsilon) {
if (scale) lengths[i] = 0;
spaces[++i] = spacing;
} else {
float x = setupLength * bone->_a, y = setupLength * bone->_c;
float length = MathUtil::sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = length;
sum += length;
}
}
if (sum > 0) {
sum = spacesCount / sum * spacing;
for (size_t i = 1; i < spacesCount; i++) {
spaces[i] *= sum;
}
}
break;
}
default: {
bool lengthSpacing = data._spacingMode == SpacingMode_Length;
for (size_t i = 0, n = spacesCount - 1; i < n;) {
BonePose *bone = bones[i];
float setupLength = bone->_bone->getData().getLength();
if (setupLength < epsilon) {
if (scale) lengths[i] = 0;
spaces[++i] = spacing;
} else {
float x = setupLength * bone->_a, y = setupLength * bone->_c;
float length = MathUtil::sqrt(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? MathUtil::max(0.0f, setupLength + spacing) : spacing) * length / setupLength;
}
}
}
}
Array<float> &positions = computeWorldPositions(skeleton, *pathAttachment, (int) spacesCount, tangents);
float *positionsBuffer = positions.buffer();
float boneX = positionsBuffer[0], boneY = positionsBuffer[1], offsetRotation = data._offsetRotation;
bool tip;
if (offsetRotation == 0)
tip = data._rotateMode == RotateMode_Chain;
else {
tip = false;
BonePose &bone = _slot->getBone().getAppliedPose();
offsetRotation *= bone._a * bone._d - bone._b * bone._c > 0 ? MathUtil::Deg_Rad : -MathUtil::Deg_Rad;
}
for (size_t i = 0, ip = 3, u = skeleton._update; i < boneCount; i++, ip += 3) {
BonePose *bone = bones[i];
bone->_worldX += (boneX - bone->_worldX) * mixX;
bone->_worldY += (boneY - bone->_worldY) * mixY;
float x = positionsBuffer[ip], y = positionsBuffer[ip + 1], dx = x - boneX, dy = y - boneY;
if (scale) {
float length = lengths[i];
if (length >= epsilon) {
float s = (MathUtil::sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1;
bone->_a *= s;
bone->_c *= s;
}
}
boneX = x;
boneY = y;
if (mixRotate > 0) {
float a = bone->_a, b = bone->_b, c = bone->_c, d = bone->_d, r, cos, sin;
if (tangents)
r = positionsBuffer[ip - 1];
else if (spaces[i + 1] < epsilon)
r = positionsBuffer[ip + 2];
else
r = MathUtil::atan2(dy, dx);
r -= MathUtil::atan2(c, a);
if (tip) {
cos = MathUtil::cos(r);
sin = MathUtil::sin(r);
float length = bone->_bone->getData().getLength();
boneX += (length * (cos * a - sin * c) - dx) * mixRotate;
boneY += (length * (sin * a + cos * c) - dy) * mixRotate;
} else
r += offsetRotation;
if (r > MathUtil::Pi)
r -= MathUtil::Pi_2;
else if (r < -MathUtil::Pi)
r += MathUtil::Pi_2;
r *= mixRotate;
cos = MathUtil::cos(r);
sin = MathUtil::sin(r);
bone->_a = cos * a - sin * c;
bone->_b = cos * b - sin * d;
bone->_c = sin * a + cos * c;
bone->_d = sin * b + cos * d;
}
bone->modifyWorld((int) u);
}
}
void PathConstraint::sort(Skeleton &skeleton) {
int slotIndex = _slot->getData().getIndex();
Bone &slotBone = _slot->getBone();
if (skeleton.getSkin() != NULL) sortPathSlot(skeleton, *skeleton.getSkin(), slotIndex, slotBone);
if (skeleton.getData().getDefaultSkin() != NULL && skeleton.getData().getDefaultSkin() != skeleton.getSkin())
sortPathSlot(skeleton, *skeleton.getData().getDefaultSkin(), slotIndex, slotBone);
sortPath(skeleton, _slot->_pose._attachment, slotBone);
BonePose **bones = _bones.buffer();
size_t boneCount = _bones.size();
for (size_t i = 0; i < boneCount; i++) {
Bone *bone = bones[i]->_bone;
skeleton.sortBone(bone);
skeleton.constrained(*bone);
}
skeleton._updateCache.add(this);
for (size_t i = 0; i < boneCount; i++) skeleton.sortReset(bones[i]->_bone->getChildren());
for (size_t i = 0; i < boneCount; i++) bones[i]->_bone->_sorted = true;
}
bool PathConstraint::isSourceActive() {
return _slot->getBone().isActive();
}
Array<BonePose *> &PathConstraint::getBones() {
return _bones;
}
Slot &PathConstraint::getSlot() {
return *_slot;
}
void PathConstraint::setSlot(Slot &slot) {
_slot = &slot;
}
Array<float> &PathConstraint::computeWorldPositions(Skeleton &skeleton, PathAttachment &path, int spacesCount, bool tangents) {
float position = _applied->_position;
float *spaces = _spaces.buffer();
_positions.setSize(spacesCount * 3 + 2, 0);
Array<float> &out = _positions;
Array<float> &world = _world;
bool closed = path.getClosed();
int verticesLength = (int) path.getWorldVerticesLength();
int curveCount = verticesLength / 6;
int prevCurve = NONE;
float pathLength;
if (!path.getConstantSpeed()) {
Array<float> &lengths = path.getLengths();
float *lengthsBuffer = lengths.buffer();
curveCount -= closed ? 1 : 2;
pathLength = lengthsBuffer[curveCount];
if (_data._positionMode == PositionMode_Percent) position *= pathLength;
float multiplier = 0;
switch (_data._spacingMode) {
case SpacingMode_Percent:
multiplier = pathLength;
break;
case SpacingMode_Proportional:
multiplier = pathLength / spacesCount;
break;
default:
multiplier = 1;
}
world.setSize(8, 0);
float *worldBuffer = world.buffer();
for (int i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) {
float space = spaces[i] * multiplier;
position += space;
float p = position;
if (closed) {
p = MathUtil::fmod(p, pathLength);
if (p < 0) p += pathLength;
curve = 0;
} else if (p < 0) {
if (prevCurve != BEFORE) {
prevCurve = BEFORE;
path.computeWorldVertices(skeleton, *_slot, 2, 4, world, 0, 2);
}
addBeforePosition(p, world, 0, out, o);
continue;
} else if (p > pathLength) {
if (prevCurve != AFTER) {
prevCurve = AFTER;
path.computeWorldVertices(skeleton, *_slot, verticesLength - 6, 4, world, 0, 2);
}
addAfterPosition(p - pathLength, world, 0, out, o);
continue;
}
// Determine curve containing position.
for (;; curve++) {
float length = lengthsBuffer[curve];
if (p > length) continue;
if (curve == 0)
p /= length;
else {
float prev = lengthsBuffer[curve - 1];
p = (p - prev) / (length - prev);
}
break;
}
if (curve != prevCurve) {
prevCurve = curve;
if (closed && curve == curveCount) {
path.computeWorldVertices(skeleton, *_slot, verticesLength - 4, 4, world, 0, 2);
path.computeWorldVertices(skeleton, *_slot, 0, 4, world, 4, 2);
} else
path.computeWorldVertices(skeleton, *_slot, curve * 6 + 2, 8, world, 0, 2);
}
addCurvePosition(p, worldBuffer[0], worldBuffer[1], worldBuffer[2], worldBuffer[3], worldBuffer[4], worldBuffer[5], worldBuffer[6],
worldBuffer[7], out, o, tangents || (i > 0 && space < epsilon));
}
return out;
}
// World vertices.
if (closed) {
verticesLength += 2;
world.setSize(verticesLength, 0);
float *worldBuffer = world.buffer();
path.computeWorldVertices(skeleton, *_slot, 2, verticesLength - 4, world, 0, 2);
path.computeWorldVertices(skeleton, *_slot, 0, 2, world, verticesLength - 4, 2);
worldBuffer[verticesLength - 2] = worldBuffer[0];
worldBuffer[verticesLength - 1] = worldBuffer[1];
} else {
curveCount--;
verticesLength -= 4;
world.setSize(verticesLength, 0);
path.computeWorldVertices(skeleton, *_slot, 2, verticesLength, world, 0, 2);
}
float *worldBuffer = world.buffer();
// Curve lengths.
_curves.setSize(curveCount, 0);
float *curvesBuffer = _curves.buffer();
pathLength = 0;
float x1 = worldBuffer[0], y1 = worldBuffer[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0;
float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy;
for (int i = 0, w = 2; i < curveCount; i++, w += 6) {
cx1 = worldBuffer[w];
cy1 = worldBuffer[w + 1];
cx2 = worldBuffer[w + 2];
cy2 = worldBuffer[w + 3];
x2 = worldBuffer[w + 4];
y2 = worldBuffer[w + 5];
tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f;
tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f;
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f;
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f;
ddfx = tmpx * 2 + dddfx;
ddfy = tmpy * 2 + dddfy;
dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f;
dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f;
pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy);
dfx += ddfx;
dfy += ddfy;
ddfx += dddfx;
ddfy += dddfy;
pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy);
dfx += ddfx;
dfy += ddfy;
pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy);
dfx += ddfx + dddfx;
dfy += ddfy + dddfy;
pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy);
curvesBuffer[i] = pathLength;
x1 = x2;
y1 = y2;
}
if (_data._positionMode == PositionMode_Percent) position *= pathLength;
float multiplier = 0;
switch (_data._spacingMode) {
case SpacingMode_Percent:
multiplier = pathLength;
break;
case SpacingMode_Proportional:
multiplier = pathLength / spacesCount;
break;
default:
multiplier = 1;
}
float curveLength = 0;
for (int i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) {
float space = spaces[i] * multiplier;
position += space;
float p = position;
if (closed) {
p = MathUtil::fmod(p, pathLength);
if (p < 0) p += pathLength;
curve = 0;
segment = 0;
} else if (p < 0) {
addBeforePosition(p, world, 0, out, o);
continue;
} else if (p > pathLength) {
addAfterPosition(p - pathLength, world, verticesLength - 4, out, o);
continue;
}
// Determine curve containing position.
for (;; curve++) {
float length = curvesBuffer[curve];
if (p > length) continue;
if (curve == 0)
p /= length;
else {
float prev = curvesBuffer[curve - 1];
p = (p - prev) / (length - prev);
}
break;
}
// Curve segment lengths.
if (curve != prevCurve) {
prevCurve = curve;
int ii = curve * 6;
x1 = worldBuffer[ii];
y1 = worldBuffer[ii + 1];
cx1 = worldBuffer[ii + 2];
cy1 = worldBuffer[ii + 3];
cx2 = worldBuffer[ii + 4];
cy2 = worldBuffer[ii + 5];
x2 = worldBuffer[ii + 6];
y2 = worldBuffer[ii + 7];
tmpx = (x1 - cx1 * 2 + cx2) * 0.03f;
tmpy = (y1 - cy1 * 2 + cy2) * 0.03f;
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f;
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f;
ddfx = tmpx * 2 + dddfx;
ddfy = tmpy * 2 + dddfy;
dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f;
dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f;
curveLength = MathUtil::sqrt(dfx * dfx + dfy * dfy);
_segments[0] = curveLength;
for (ii = 1; ii < 8; ii++) {
dfx += ddfx;
dfy += ddfy;
ddfx += dddfx;
ddfy += dddfy;
curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy);
_segments[ii] = curveLength;
}
dfx += ddfx;
dfy += ddfy;
curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy);
_segments[8] = curveLength;
dfx += ddfx + dddfx;
dfy += ddfy + dddfy;
curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy);
_segments[9] = curveLength;
segment = 0;
}
// Weight by segment length.
p *= curveLength;
for (;; segment++) {
float length = _segments[segment];
if (p > length) continue;
if (segment == 0)
p /= length;
else {
float prev = _segments[segment - 1];
p = segment + (p - prev) / (length - prev);
}
break;
}
addCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space < epsilon));
}
return out;
}
void PathConstraint::addBeforePosition(float p, Array<float> &temp, int i, Array<float> &output, int o) {
float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = MathUtil::atan2(dy, dx);
output[o] = x1 + p * MathUtil::cos(r);
output[o + 1] = y1 + p * MathUtil::sin(r);
output[o + 2] = r;
}
void PathConstraint::addAfterPosition(float p, Array<float> &temp, int i, Array<float> &output, int o) {
float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = MathUtil::atan2(dy, dx);
output[o] = x1 + p * MathUtil::cos(r);
output[o + 1] = y1 + p * MathUtil::sin(r);
output[o + 2] = r;
}
void PathConstraint::addCurvePosition(float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2,
Array<float> &output, int o, bool tangents) {
if (p < epsilon || MathUtil::isNan(p)) {
output[o] = x1;
output[o + 1] = y1;
output[o + 2] = MathUtil::atan2(cy1 - y1, cx1 - x1);
return;
}
float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u;
float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p;
float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
output[o] = x;
output[o + 1] = y;
if (tangents) {
if (p < 0.001f)
output[o + 2] = MathUtil::atan2(cy1 - y1, cx1 - x1);
else
output[o + 2] = MathUtil::atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
}
}
void PathConstraint::sortPathSlot(Skeleton &skeleton, Skin &skin, int slotIndex, Bone &slotBone) {
Skin::AttachmentMap::Entries entries = skin.getAttachments();
while (entries.hasNext()) {
Skin::AttachmentMap::Entry &entry = entries.next();
if (entry._slotIndex == (size_t) slotIndex) sortPath(skeleton, entry._attachment, slotBone);
}
}
void PathConstraint::sortPath(Skeleton &skeleton, Attachment *attachment, Bone &slotBone) {
if (attachment == NULL || !attachment->getRTTI().instanceOf(PathAttachment::rtti)) return;
PathAttachment *pathAttachment = static_cast<PathAttachment *>(attachment);
Array<int> &pathBones = pathAttachment->getBones();
if (pathBones.size() == 0)
skeleton.sortBone(&slotBone);
else {
Array<Bone *> &bones = skeleton._bones;
for (size_t i = 0, n = pathBones.size(); i < n;) {
int nn = pathBones[i++];
nn += i;
while (i < (size_t) nn) skeleton.sortBone(bones[pathBones[i++]]);
}
}
}

View File

@ -1,92 +0,0 @@
/******************************************************************************
* 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 <spine/PathConstraintData.h>
#include <spine/PathConstraint.h>
#include <spine/BoneData.h>
#include <spine/SlotData.h>
#include <spine/Skeleton.h>
using namespace spine;
RTTI_IMPL(PathConstraintData, ConstraintData)
PathConstraintData::PathConstraintData(const String &name)
: ConstraintDataGeneric<PathConstraint, PathConstraintPose>(name), _slot(NULL), _positionMode(PositionMode_Fixed),
_spacingMode(SpacingMode_Length), _rotateMode(RotateMode_Tangent), _offsetRotation(0) {
}
Array<BoneData *> &PathConstraintData::getBones() {
return _bones;
}
SlotData &PathConstraintData::getSlot() {
return *_slot;
}
void PathConstraintData::setSlot(SlotData &slot) {
_slot = &slot;
}
PositionMode PathConstraintData::getPositionMode() {
return _positionMode;
}
void PathConstraintData::setPositionMode(PositionMode positionMode) {
_positionMode = positionMode;
}
SpacingMode PathConstraintData::getSpacingMode() {
return _spacingMode;
}
void PathConstraintData::setSpacingMode(SpacingMode spacingMode) {
_spacingMode = spacingMode;
}
RotateMode PathConstraintData::getRotateMode() {
return _rotateMode;
}
void PathConstraintData::setRotateMode(RotateMode rotateMode) {
_rotateMode = rotateMode;
}
float PathConstraintData::getOffsetRotation() {
return _offsetRotation;
}
void PathConstraintData::setOffsetRotation(float offsetRotation) {
_offsetRotation = offsetRotation;
}
Constraint &PathConstraintData::create(Skeleton &skeleton) {
return *(new (__FILE__, __LINE__) PathConstraint(*this, skeleton));
}

View File

@ -1,123 +0,0 @@
/******************************************************************************
* 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 <spine/PathConstraintMixTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/PathConstraint.h>
#include <spine/PathConstraintData.h>
#include <spine/PathConstraintPose.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL_MULTI(PathConstraintMixTimeline, CurveTimeline, ConstraintTimeline)
PathConstraintMixTimeline::PathConstraintMixTimeline(size_t frameCount, size_t bezierCount, int constraintIndex)
: CurveTimeline(frameCount, PathConstraintMixTimeline::ENTRIES, bezierCount), ConstraintTimeline(), _constraintIndex(constraintIndex) {
PropertyId ids[] = {((PropertyId) Property_PathConstraintMix << 32) | constraintIndex};
setPropertyIds(ids, 1);
_additive = true;
}
PathConstraintMixTimeline::~PathConstraintMixTimeline() {
}
void PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add,
bool out, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(out);
PathConstraint *constraint = (PathConstraint *) skeleton._constraints[_constraintIndex];
if (!constraint->isActive()) return;
PathConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
if (time < _frames[0]) {
if (fromSetup) {
PathConstraintPose &setup = constraint->_data._setup;
pose._mixRotate = setup._mixRotate;
pose._mixX = setup._mixX;
pose._mixY = setup._mixY;
}
return;
}
float rotate, x, y;
int i = Animation::search(_frames, time, PathConstraintMixTimeline::ENTRIES);
int curveType = (int) _curves[i >> 2];
switch (curveType) {
case LINEAR: {
float before = _frames[i];
rotate = _frames[i + ROTATE];
x = _frames[i + X];
y = _frames[i + Y];
float t = (time - before) / (_frames[i + ENTRIES] - before);
rotate += (_frames[i + ENTRIES + ROTATE] - rotate) * t;
x += (_frames[i + ENTRIES + X] - x) * t;
y += (_frames[i + ENTRIES + Y] - y) * t;
break;
}
case STEPPED: {
rotate = _frames[i + ROTATE];
x = _frames[i + X];
y = _frames[i + Y];
break;
}
default: {
rotate = getBezierValue(time, i, ROTATE, curveType - BEZIER);
x = getBezierValue(time, i, X, curveType + BEZIER_SIZE - BEZIER);
y = getBezierValue(time, i, Y, curveType + BEZIER_SIZE * 2 - BEZIER);
}
}
PathConstraintPose &base = fromSetup ? constraint->_data._setup : pose;
if (add) {
pose._mixRotate = base._mixRotate + rotate * alpha;
pose._mixX = base._mixX + x * alpha;
pose._mixY = base._mixY + y * alpha;
} else {
pose._mixRotate = base._mixRotate + (rotate - base._mixRotate) * alpha;
pose._mixX = base._mixX + (x - base._mixX) * alpha;
pose._mixY = base._mixY + (y - base._mixY) * alpha;
}
}
void PathConstraintMixTimeline::setFrame(int frame, float time, float mixRotate, float mixX, float mixY) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + ROTATE] = mixRotate;
_frames[frame + X] = mixX;
_frames[frame + Y] = mixY;
}

View File

@ -1,86 +0,0 @@
/******************************************************************************
* 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 <spine/PathConstraintPose.h>
using namespace spine;
PathConstraintPose::PathConstraintPose() : Pose<PathConstraintPose>(), _position(0), _spacing(0), _mixRotate(0), _mixX(0), _mixY(0) {
}
PathConstraintPose::~PathConstraintPose() {
}
void PathConstraintPose::set(PathConstraintPose &pose) {
_position = pose._position;
_spacing = pose._spacing;
_mixRotate = pose._mixRotate;
_mixX = pose._mixX;
_mixY = pose._mixY;
}
float PathConstraintPose::getPosition() {
return _position;
}
void PathConstraintPose::setPosition(float position) {
_position = position;
}
float PathConstraintPose::getSpacing() {
return _spacing;
}
void PathConstraintPose::setSpacing(float spacing) {
_spacing = spacing;
}
float PathConstraintPose::getMixRotate() {
return _mixRotate;
}
void PathConstraintPose::setMixRotate(float mixRotate) {
_mixRotate = mixRotate;
}
float PathConstraintPose::getMixX() {
return _mixX;
}
void PathConstraintPose::setMixX(float mixX) {
_mixX = mixX;
}
float PathConstraintPose::getMixY() {
return _mixY;
}
void PathConstraintPose::setMixY(float mixY) {
_mixY = mixY;
}

View File

@ -1,66 +0,0 @@
/******************************************************************************
* 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 <spine/PathConstraintPositionTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/PathConstraint.h>
#include <spine/PathConstraintData.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(PathConstraintPositionTimeline, ConstraintTimeline1)
PathConstraintPositionTimeline::PathConstraintPositionTimeline(size_t frameCount, size_t bezierCount, int constraintIndex)
: ConstraintTimeline1(frameCount, bezierCount, constraintIndex, Property_PathConstraintPosition) {
_additive = true;
}
PathConstraintPositionTimeline::~PathConstraintPositionTimeline() {
}
void PathConstraintPositionTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup,
bool add, bool out, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(out);
PathConstraint *constraint = (PathConstraint *) skeleton._constraints[_constraintIndex];
if (constraint->isActive()) {
PathConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
PathConstraintData &data = constraint->_data;
pose._position = getAbsoluteValue(time, alpha, fromSetup, add, pose._position, data._setup._position);
}
}

View File

@ -1,65 +0,0 @@
/******************************************************************************
* 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 <spine/PathConstraintSpacingTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/PathConstraint.h>
#include <spine/PathConstraintData.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(PathConstraintSpacingTimeline, ConstraintTimeline1)
PathConstraintSpacingTimeline::PathConstraintSpacingTimeline(size_t frameCount, size_t bezierCount, int constraintIndex)
: ConstraintTimeline1(frameCount, bezierCount, constraintIndex, Property_PathConstraintSpacing) {
}
PathConstraintSpacingTimeline::~PathConstraintSpacingTimeline() {
}
void PathConstraintSpacingTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup,
bool add, bool out, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(out);
PathConstraint *constraint = (PathConstraint *) skeleton._constraints[_constraintIndex];
if (constraint->isActive()) {
PathConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
PathConstraintData &data = constraint->_data;
pose._spacing = getAbsoluteValue(time, alpha, fromSetup, false, pose._spacing, data._setup._spacing);
}
}

View File

@ -1,292 +0,0 @@
/******************************************************************************
* 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 <spine/PhysicsConstraint.h>
#include <spine/PhysicsConstraintData.h>
#include <spine/PhysicsConstraintPose.h>
#include <spine/BonePose.h>
#include <spine/Skeleton.h>
#include <spine/SkeletonData.h>
#include <spine/BoneData.h>
#include <spine/Bone.h>
#include <spine/MathUtil.h>
using namespace spine;
RTTI_IMPL(PhysicsConstraint, Constraint)
PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData &data, Skeleton &skeleton)
: PhysicsConstraintBase(data), _reset(true), _ux(0), _uy(0), _cx(0), _cy(0), _tx(0), _ty(0), _xOffset(0), _xLag(0), _xVelocity(0), _yOffset(0),
_yLag(0), _yVelocity(0), _rotateOffset(0), _rotateLag(0), _rotateVelocity(0), _scaleOffset(0), _scaleLag(0), _scaleVelocity(0), _remaining(0),
_lastTime(0) {
_bone = &skeleton._bones[(size_t) data._bone->getIndex()]->_constrained;
}
PhysicsConstraint &PhysicsConstraint::copy(Skeleton &skeleton) {
PhysicsConstraint *copy = new (__FILE__, __LINE__) PhysicsConstraint(_data, skeleton);
copy->_pose.set(_pose);
return *copy;
}
void PhysicsConstraint::reset(Skeleton &skeleton) {
_remaining = 0;
_lastTime = skeleton.getTime();
_reset = true;
_xOffset = 0;
_xLag = 0;
_xVelocity = 0;
_yOffset = 0;
_yLag = 0;
_yVelocity = 0;
_rotateOffset = 0;
_rotateLag = 0;
_rotateVelocity = 0;
_scaleOffset = 0;
_scaleLag = 0;
_scaleVelocity = 0;
}
void PhysicsConstraint::translate(float x, float y) {
_ux -= x;
_uy -= y;
_cx -= x;
_cy -= y;
}
void PhysicsConstraint::rotate(float x, float y, float degrees) {
float r = degrees * MathUtil::Deg_Rad, cosVal = MathUtil::cos(r), sinVal = MathUtil::sin(r);
float dx = _cx - x, dy = _cy - y;
translate(dx * cosVal - dy * sinVal - dx, dx * sinVal + dy * cosVal - dy);
}
void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) {
PhysicsConstraintPose &p = *_applied;
float mix = p._mix;
if (mix == 0) return;
bool x = _data._x > 0, y = _data._y > 0, rotateOrShearX = _data._rotate > 0 || _data._shearX > 0, scaleX = _data._scaleX > 0;
BonePose *bone = _bone;
float l = bone->_bone->_data.getLength(), t = _data._step, z = 0;
switch (physics) {
case Physics_None:
return;
case Physics_Reset:
reset(skeleton);
// Fall through.
case Physics_Update: {
float delta = MathUtil::max(skeleton._time - _lastTime, 0.0f), aa = _remaining;
_remaining += delta;
_lastTime = skeleton._time;
float bx = bone->_worldX, by = bone->_worldY;
if (_reset) {
_reset = false;
_ux = bx;
_uy = by;
} else {
float a = _remaining, i = p._inertia, f = skeleton._data.getReferenceScale(), d = -1, m = 0, e = 0, qx = _data._limit * delta,
qy = qx * MathUtil::abs(skeleton.getScaleY());
qx *= MathUtil::abs(skeleton._scaleX);
if (x || y) {
if (x) {
float u = (_ux - bx) * i;
_xOffset += u > qx ? qx : u < -qx ? -qx : u;
_ux = bx;
}
if (y) {
float u = (_uy - by) * i;
_yOffset += u > qy ? qy : u < -qy ? -qy : u;
_uy = by;
}
if (a >= t) {
float xs = _xOffset, ys = _yOffset;
d = MathUtil::pow(p._damping, 60 * t);
m = t * p._massInverse;
e = p._strength;
float w = f * p._wind, g = f * p._gravity;
float ax = (w * skeleton._windX + g * skeleton._gravityX) * skeleton._scaleX;
float ay = (w * skeleton._windY + g * skeleton._gravityY) * skeleton.getScaleY();
do {
if (x) {
_xVelocity += (ax - _xOffset * e) * m;
_xOffset += _xVelocity * t;
_xVelocity *= d;
}
if (y) {
_yVelocity -= (ay + _yOffset * e) * m;
_yOffset += _yVelocity * t;
_yVelocity *= d;
}
a -= t;
} while (a >= t);
_xLag = _xOffset - xs;
_yLag = _yOffset - ys;
}
z = MathUtil::max(0.0f, 1 - a / t);
if (x) bone->_worldX += (_xOffset - _xLag * z) * mix * _data._x;
if (y) bone->_worldY += (_yOffset - _yLag * z) * mix * _data._y;
}
if (rotateOrShearX || scaleX) {
float ca = MathUtil::atan2(bone->_c, bone->_a), c, s, mr = 0, dx = _cx - bone->_worldX, dy = _cy - bone->_worldY;
if (dx > qx)
dx = qx;
else if (dx < -qx)
dx = -qx;
if (dy > qy)
dy = qy;
else if (dy < -qy)
dy = -qy;
if (rotateOrShearX) {
mr = (_data._rotate + _data._shearX) * mix;
z = _rotateLag * MathUtil::max(0.0f, 1 - aa / t);
float r = MathUtil::atan2(dy + _ty, dx + _tx) - ca - (_rotateOffset - z) * mr;
_rotateOffset += (r - MathUtil::ceil(r * MathUtil::InvPi_2 - 0.5f) * MathUtil::Pi_2) * i;
r = (_rotateOffset - z) * mr + ca;
c = MathUtil::cos(r);
s = MathUtil::sin(r);
if (scaleX) {
r = l * bone->getWorldScaleX();
if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
}
} else {
c = MathUtil::cos(ca);
s = MathUtil::sin(ca);
float r = l * bone->getWorldScaleX() - _scaleLag * MathUtil::max(0.0f, 1 - aa / t);
if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
}
a = _remaining;
if (a >= t) {
if (d == -1) {
d = MathUtil::pow(p._damping, 60 * t);
m = t * p._massInverse;
e = p._strength;
}
float ax = p._wind * skeleton._windX + p._gravity * skeleton._gravityX;
float ay = p._wind * skeleton._windY + p._gravity * skeleton._gravityY;
float rs = _rotateOffset, ss = _scaleOffset, h = l / f;
while (true) {
a -= t;
if (scaleX) {
_scaleVelocity += (ax * c - ay * s - _scaleOffset * e) * m;
_scaleOffset += _scaleVelocity * t;
_scaleVelocity *= d;
}
if (rotateOrShearX) {
_rotateVelocity -= ((ax * s + ay * c) * h + _rotateOffset * e) * m;
_rotateOffset += _rotateVelocity * t;
_rotateVelocity *= d;
if (a < t) break;
float r = _rotateOffset * mr + ca;
c = MathUtil::cos(r);
s = MathUtil::sin(r);
} else if (a < t)
break;
}
_rotateLag = _rotateOffset - rs;
_scaleLag = _scaleOffset - ss;
}
z = MathUtil::max(0.0f, 1 - a / t);
}
_remaining = a;
}
_cx = bone->_worldX;
_cy = bone->_worldY;
break;
}
case Physics_Pose: {
z = MathUtil::max(0.0f, 1 - _remaining / t);
if (x) bone->_worldX += (_xOffset - _xLag * z) * mix * _data._x;
if (y) bone->_worldY += (_yOffset - _yLag * z) * mix * _data._y;
break;
}
}
if (rotateOrShearX) {
float o = (_rotateOffset - _rotateLag * z) * mix, s, c, a;
if (_data._shearX > 0) {
float r = 0;
if (_data._rotate > 0) {
r = o * _data._rotate;
s = MathUtil::sin(r);
c = MathUtil::cos(r);
a = bone->_b;
bone->_b = c * a - s * bone->_d;
bone->_d = s * a + c * bone->_d;
}
r += o * _data._shearX;
s = MathUtil::sin(r);
c = MathUtil::cos(r);
a = bone->_a;
bone->_a = c * a - s * bone->_c;
bone->_c = s * a + c * bone->_c;
} else {
o *= _data._rotate;
s = MathUtil::sin(o);
c = MathUtil::cos(o);
a = bone->_a;
bone->_a = c * a - s * bone->_c;
bone->_c = s * a + c * bone->_c;
a = bone->_b;
bone->_b = c * a - s * bone->_d;
bone->_d = s * a + c * bone->_d;
}
}
if (scaleX) {
float s = 1 + (_scaleOffset - _scaleLag * z) * mix * _data._scaleX;
bone->_a *= s;
bone->_c *= s;
}
if (physics != Physics_Pose) {
_tx = l * bone->_a;
_ty = l * bone->_c;
}
bone->modifyWorld(skeleton._update);
}
void PhysicsConstraint::sort(Skeleton &skeleton) {
Bone *bone = _bone->_bone;
skeleton.sortBone(bone);
skeleton._updateCache.add(this);
skeleton.sortReset(bone->_children);
skeleton.constrained(*bone);
}
bool PhysicsConstraint::isSourceActive() {
return _bone->_bone->isActive();
}
BonePose &PhysicsConstraint::getBone() {
return *_bone;
}
void PhysicsConstraint::setBone(BonePose &bone) {
_bone = &bone;
}

View File

@ -1,167 +0,0 @@
/******************************************************************************
* 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 <spine/PhysicsConstraintData.h>
#include <spine/PhysicsConstraint.h>
#include <spine/BoneData.h>
#include <spine/Skeleton.h>
using namespace spine;
RTTI_IMPL(PhysicsConstraintData, ConstraintData)
PhysicsConstraintData::PhysicsConstraintData(const String &name)
: ConstraintDataGeneric<PhysicsConstraint, PhysicsConstraintPose>(name), _bone(NULL), _x(0), _y(0), _rotate(0), _scaleX(0), _shearX(0), _limit(0),
_step(0), _inertiaGlobal(false), _strengthGlobal(false), _dampingGlobal(false), _massGlobal(false), _windGlobal(false), _gravityGlobal(false),
_mixGlobal(false) {
}
BoneData &PhysicsConstraintData::getBone() {
return *_bone;
}
void PhysicsConstraintData::setBone(BoneData &bone) {
_bone = &bone;
}
float PhysicsConstraintData::getStep() {
return _step;
}
void PhysicsConstraintData::setStep(float step) {
_step = step;
}
float PhysicsConstraintData::getX() {
return _x;
}
void PhysicsConstraintData::setX(float x) {
_x = x;
}
float PhysicsConstraintData::getY() {
return _y;
}
void PhysicsConstraintData::setY(float y) {
_y = y;
}
float PhysicsConstraintData::getRotate() {
return _rotate;
}
void PhysicsConstraintData::setRotate(float rotate) {
_rotate = rotate;
}
float PhysicsConstraintData::getScaleX() {
return _scaleX;
}
void PhysicsConstraintData::setScaleX(float scaleX) {
_scaleX = scaleX;
}
float PhysicsConstraintData::getShearX() {
return _shearX;
}
void PhysicsConstraintData::setShearX(float shearX) {
_shearX = shearX;
}
float PhysicsConstraintData::getLimit() {
return _limit;
}
void PhysicsConstraintData::setLimit(float limit) {
_limit = limit;
}
bool PhysicsConstraintData::getInertiaGlobal() {
return _inertiaGlobal;
}
void PhysicsConstraintData::setInertiaGlobal(bool inertiaGlobal) {
_inertiaGlobal = inertiaGlobal;
}
bool PhysicsConstraintData::getStrengthGlobal() {
return _strengthGlobal;
}
void PhysicsConstraintData::setStrengthGlobal(bool strengthGlobal) {
_strengthGlobal = strengthGlobal;
}
bool PhysicsConstraintData::getDampingGlobal() {
return _dampingGlobal;
}
void PhysicsConstraintData::setDampingGlobal(bool dampingGlobal) {
_dampingGlobal = dampingGlobal;
}
bool PhysicsConstraintData::getMassGlobal() {
return _massGlobal;
}
void PhysicsConstraintData::setMassGlobal(bool massGlobal) {
_massGlobal = massGlobal;
}
bool PhysicsConstraintData::getWindGlobal() {
return _windGlobal;
}
void PhysicsConstraintData::setWindGlobal(bool windGlobal) {
_windGlobal = windGlobal;
}
bool PhysicsConstraintData::getGravityGlobal() {
return _gravityGlobal;
}
void PhysicsConstraintData::setGravityGlobal(bool gravityGlobal) {
_gravityGlobal = gravityGlobal;
}
bool PhysicsConstraintData::getMixGlobal() {
return _mixGlobal;
}
void PhysicsConstraintData::setMixGlobal(bool mixGlobal) {
_mixGlobal = mixGlobal;
}
Constraint &PhysicsConstraintData::create(Skeleton &skeleton) {
return *(new (__FILE__, __LINE__) PhysicsConstraint(*this, skeleton));
}

View File

@ -1,105 +0,0 @@
/******************************************************************************
* 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 <spine/PhysicsConstraintPose.h>
using namespace spine;
PhysicsConstraintPose::PhysicsConstraintPose()
: Pose<PhysicsConstraintPose>(), _inertia(0), _strength(0), _damping(0), _massInverse(0), _wind(0), _gravity(0), _mix(0) {
}
PhysicsConstraintPose::~PhysicsConstraintPose() {
}
void PhysicsConstraintPose::set(PhysicsConstraintPose &pose) {
_inertia = pose._inertia;
_strength = pose._strength;
_damping = pose._damping;
_massInverse = pose._massInverse;
_wind = pose._wind;
_gravity = pose._gravity;
_mix = pose._mix;
}
float PhysicsConstraintPose::getInertia() {
return _inertia;
}
void PhysicsConstraintPose::setInertia(float inertia) {
_inertia = inertia;
}
float PhysicsConstraintPose::getStrength() {
return _strength;
}
void PhysicsConstraintPose::setStrength(float strength) {
_strength = strength;
}
float PhysicsConstraintPose::getDamping() {
return _damping;
}
void PhysicsConstraintPose::setDamping(float damping) {
_damping = damping;
}
float PhysicsConstraintPose::getMassInverse() {
return _massInverse;
}
void PhysicsConstraintPose::setMassInverse(float massInverse) {
_massInverse = massInverse;
}
float PhysicsConstraintPose::getWind() {
return _wind;
}
void PhysicsConstraintPose::setWind(float wind) {
_wind = wind;
}
float PhysicsConstraintPose::getGravity() {
return _gravity;
}
void PhysicsConstraintPose::setGravity(float gravity) {
_gravity = gravity;
}
float PhysicsConstraintPose::getMix() {
return _mix;
}
void PhysicsConstraintPose::setMix(float mix) {
_mix = mix;
}

View File

@ -1,110 +0,0 @@
/******************************************************************************
* 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 <spine/PhysicsConstraintTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/PhysicsConstraint.h>
#include <cfloat>
using namespace spine;
RTTI_IMPL_MULTI(PhysicsConstraintTimeline, CurveTimeline, ConstraintTimeline)
RTTI_IMPL(PhysicsConstraintInertiaTimeline, PhysicsConstraintTimeline)
RTTI_IMPL(PhysicsConstraintStrengthTimeline, PhysicsConstraintTimeline)
RTTI_IMPL(PhysicsConstraintDampingTimeline, PhysicsConstraintTimeline)
RTTI_IMPL(PhysicsConstraintMassTimeline, PhysicsConstraintTimeline)
RTTI_IMPL(PhysicsConstraintWindTimeline, PhysicsConstraintTimeline)
RTTI_IMPL(PhysicsConstraintGravityTimeline, PhysicsConstraintTimeline)
RTTI_IMPL(PhysicsConstraintMixTimeline, PhysicsConstraintTimeline)
RTTI_IMPL_MULTI(PhysicsConstraintResetTimeline, Timeline, ConstraintTimeline)
PhysicsConstraintTimeline::PhysicsConstraintTimeline(size_t frameCount, size_t bezierCount, int constraintIndex, Property property)
: CurveTimeline1(frameCount, bezierCount), ConstraintTimeline(), _constraintIndex(constraintIndex) {
PropertyId ids[] = {((PropertyId) property << 32) | constraintIndex};
setPropertyIds(ids, 1);
}
void PhysicsConstraintTimeline::apply(Skeleton &skeleton, float, float time, Array<Event *> *, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(out);
if (add && !_additive) add = false;
if (_constraintIndex == -1) {
float value = time >= _frames[0] ? getCurveValue(time) : 0;
Array<PhysicsConstraint *> &physicsConstraints = skeleton.getPhysicsConstraints();
for (size_t i = 0; i < physicsConstraints.size(); i++) {
PhysicsConstraint *constraint = physicsConstraints[i];
if (constraint->isActive() && global(constraint->_data)) {
PhysicsConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
set(pose, getAbsoluteValue(time, alpha, fromSetup, add, get(pose), get(constraint->_data._setup), value));
}
}
} else {
PhysicsConstraint *constraint = static_cast<PhysicsConstraint *>(skeleton.getConstraints()[_constraintIndex]);
if (constraint->isActive()) {
PhysicsConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
set(pose, getAbsoluteValue(time, alpha, fromSetup, add, get(pose), get(constraint->_data._setup)));
}
}
}
void PhysicsConstraintResetTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *, float alpha, bool fromSetup, bool add,
bool out, bool appliedPose) {
PhysicsConstraint *constraint = nullptr;
if (_constraintIndex != -1) {
constraint = static_cast<PhysicsConstraint *>(skeleton.getConstraints()[_constraintIndex]);
if (!constraint->isActive()) return;
}
if (lastTime > time) {// Apply after lastTime for looped animations.
apply(skeleton, lastTime, FLT_MAX, nullptr, alpha, false, false, false, false);
lastTime = -1;
} else if (lastTime >= _frames[_frames.size() - 1])// Last time is after last frame.
return;
if (time < _frames[0]) return;
if (lastTime < _frames[0] || time >= _frames[Animation::search(_frames, lastTime) + 1]) {
if (constraint != nullptr)
constraint->reset(skeleton);
else {
Array<PhysicsConstraint *> &physicsConstraints = skeleton.getPhysicsConstraints();
for (size_t i = 0; i < physicsConstraints.size(); i++) {
constraint = physicsConstraints[i];
if (constraint->isActive()) constraint->reset(skeleton);
}
}
}
}

View File

@ -1,90 +0,0 @@
/******************************************************************************
* 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 <spine/PointAttachment.h>
#include <spine/Bone.h>
#include <spine/MathUtil.h>
using namespace spine;
RTTI_IMPL(PointAttachment, Attachment)
PointAttachment::PointAttachment(const String &name) : Attachment(name), _x(0), _y(0), _rotation(0), _color(0.9451f, 0.9451f, 0, 1) {
}
float PointAttachment::getX() {
return _x;
}
void PointAttachment::setX(float inValue) {
_x = inValue;
}
float PointAttachment::getY() {
return _y;
}
void PointAttachment::setY(float inValue) {
_y = inValue;
}
float PointAttachment::getRotation() {
return _rotation;
}
void PointAttachment::setRotation(float inValue) {
_rotation = inValue;
}
Color &PointAttachment::getColor() {
return _color;
}
void PointAttachment::computeWorldPosition(BonePose &bone, float &ox, float &oy) {
ox = _x * bone.getA() + _y * bone.getB() + bone.getWorldX();
oy = _x * bone.getC() + _y * bone.getD() + bone.getWorldY();
}
float PointAttachment::computeWorldRotation(BonePose &bone) {
float r = _rotation * MathUtil::Deg_Rad, cosine = MathUtil::cos(r), sine = MathUtil::sin(r);
float x = cosine * bone.getA() + sine * bone.getB();
float y = cosine * bone.getC() + sine * bone.getD();
return MathUtil::atan2Deg(y, x);
}
Attachment &PointAttachment::copy() {
PointAttachment *copy = new (__FILE__, __LINE__) PointAttachment(getName());
copy->_x = _x;
copy->_y = _y;
copy->_rotation = _rotation;
copy->_color.set(_color);
return *copy;
}

View File

@ -1,83 +0,0 @@
/******************************************************************************
* 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 <spine/RTTI.h>
#include <spine/SpineString.h>
using namespace spine;
RTTI::RTTI(const char *className) : _className(className), _pBaseRTTI(NULL), _interfaceCount(0) {
_interfaces[0] = NULL;
_interfaces[1] = NULL;
_interfaces[2] = NULL;
}
RTTI::RTTI(const char *className, const RTTI &baseRTTI) : _className(className), _pBaseRTTI(&baseRTTI), _interfaceCount(0) {
_interfaces[0] = NULL;
_interfaces[1] = NULL;
_interfaces[2] = NULL;
}
RTTI::RTTI(const char *className, const RTTI &baseRTTI, const RTTI *interface1, const RTTI *interface2, const RTTI *interface3)
: _className(className), _pBaseRTTI(&baseRTTI), _interfaceCount(0) {
_interfaces[0] = interface1;
_interfaces[1] = interface2;
_interfaces[2] = interface3;
if (interface1) _interfaceCount++;
if (interface2) _interfaceCount++;
if (interface3) _interfaceCount++;
}
const char *RTTI::getClassName() const {
return _className;
}
bool RTTI::isExactly(const RTTI &rtti) const {
return !strcmp(this->_className, rtti._className);
}
bool RTTI::instanceOf(const RTTI &rtti) const {
// Check the main inheritance chain
const RTTI *pCompare = this;
while (pCompare) {
if (!strcmp(pCompare->_className, rtti._className)) return true;
// Check interfaces at this level of the hierarchy
for (int i = 0; i < pCompare->_interfaceCount; i++) {
if (pCompare->_interfaces[i] && !strcmp(pCompare->_interfaces[i]->_className, rtti._className)) {
return true;
}
}
pCompare = pCompare->_pBaseRTTI;
}
return false;
}

View File

@ -1,257 +0,0 @@
/******************************************************************************
* 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 <spine/RegionAttachment.h>
#include <spine/Atlas.h>
#include <spine/Bone.h>
#include <spine/MathUtil.h>
#include <spine/Slot.h>
#include <spine/SlotPose.h>
#include <assert.h>
using namespace spine;
RTTI_IMPL(RegionAttachment, Attachment)
const int RegionAttachment::BLX = 0;
const int RegionAttachment::BLY = 1;
const int RegionAttachment::ULX = 2;
const int RegionAttachment::ULY = 3;
const int RegionAttachment::URX = 4;
const int RegionAttachment::URY = 5;
const int RegionAttachment::BRX = 6;
const int RegionAttachment::BRY = 7;
RegionAttachment::RegionAttachment(const String &name, Sequence *sequence)
: Attachment(name), _sequence(sequence), _x(0), _y(0), _scaleX(1), _scaleY(1), _rotation(0), _width(0), _height(0), _path(), _color(1, 1, 1, 1) {
assert(sequence);
}
RegionAttachment::~RegionAttachment() {
delete _sequence;
}
void RegionAttachment::computeWorldVertices(Slot &slot, Array<float> &vertexOffsets, Array<float> &worldVertices, size_t offset, size_t stride) {
assert(worldVertices.size() >= (offset + 8));
computeWorldVertices(slot, vertexOffsets.buffer(), worldVertices.buffer(), offset, stride);
}
void RegionAttachment::computeWorldVertices(Slot &slot, float *vertexOffsets, float *worldVertices, size_t offset, size_t stride) {
BonePose &bone = slot.getBone().getAppliedPose();
float x = bone.getWorldX(), y = bone.getWorldY();
float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD();
float offsetX = vertexOffsets[BRX];
float offsetY = vertexOffsets[BRY];
worldVertices[offset] = offsetX * a + offsetY * b + x;
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
offset += stride;
offsetX = vertexOffsets[BLX];
offsetY = vertexOffsets[BLY];
worldVertices[offset] = offsetX * a + offsetY * b + x;
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
offset += stride;
offsetX = vertexOffsets[ULX];
offsetY = vertexOffsets[ULY];
worldVertices[offset] = offsetX * a + offsetY * b + x;
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
offset += stride;
offsetX = vertexOffsets[URX];
offsetY = vertexOffsets[URY];
worldVertices[offset] = offsetX * a + offsetY * b + x;
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
}
Array<float> &RegionAttachment::getOffsets(SlotPose &pose) {
return _sequence->getOffsets(_sequence->resolveIndex(pose));
}
float RegionAttachment::getX() {
return _x;
}
void RegionAttachment::setX(float inValue) {
_x = inValue;
}
float RegionAttachment::getY() {
return _y;
}
void RegionAttachment::setY(float inValue) {
_y = inValue;
}
float RegionAttachment::getScaleX() {
return _scaleX;
}
void RegionAttachment::setScaleX(float inValue) {
_scaleX = inValue;
}
float RegionAttachment::getScaleY() {
return _scaleY;
}
void RegionAttachment::setScaleY(float inValue) {
_scaleY = inValue;
}
float RegionAttachment::getRotation() {
return _rotation;
}
void RegionAttachment::setRotation(float inValue) {
_rotation = inValue;
}
float RegionAttachment::getWidth() {
return _width;
}
void RegionAttachment::setWidth(float inValue) {
_width = inValue;
}
float RegionAttachment::getHeight() {
return _height;
}
void RegionAttachment::setHeight(float inValue) {
_height = inValue;
}
Sequence &RegionAttachment::getSequence() {
return *_sequence;
}
void RegionAttachment::updateSequence() {
_sequence->update(*this);
}
const String &RegionAttachment::getPath() {
return _path;
}
void RegionAttachment::setPath(const String &inValue) {
_path = inValue;
}
Color &RegionAttachment::getColor() {
return _color;
}
Attachment &RegionAttachment::copy() {
RegionAttachment *copy = new (__FILE__, __LINE__) RegionAttachment(getName(), new (__FILE__, __LINE__) Sequence(*_sequence));
copy->setTimelineAttachment(getTimelineAttachment());
copy->_path = _path;
copy->_x = _x;
copy->_y = _y;
copy->_scaleX = _scaleX;
copy->_scaleY = _scaleY;
copy->_rotation = _rotation;
copy->_width = _width;
copy->_height = _height;
copy->_color.set(_color);
return *copy;
}
void RegionAttachment::computeUVs(TextureRegion *region, float x, float y, float scaleX, float scaleY, float rotation, float width, float height,
Array<float> &offset, Array<float> &uvs) {
float localX2 = width / 2, localY2 = height / 2;
float localX = -localX2, localY = -localY2;
bool rotated = false;
if (region != NULL && region->getRTTI().instanceOf(AtlasRegion::rtti)) {
AtlasRegion *r = static_cast<AtlasRegion *>(region);
localX += r->_offsetX / r->_originalWidth * width;
localY += r->_offsetY / r->_originalHeight * height;
if (r->_degrees == 90) {
rotated = true;
localX2 -= (r->_originalWidth - r->_offsetX - r->_packedHeight) / r->_originalWidth * width;
localY2 -= (r->_originalHeight - r->_offsetY - r->_packedWidth) / r->_originalHeight * height;
} else {
localX2 -= (r->_originalWidth - r->_offsetX - r->_packedWidth) / r->_originalWidth * width;
localY2 -= (r->_originalHeight - r->_offsetY - r->_packedHeight) / r->_originalHeight * height;
}
}
localX *= scaleX;
localY *= scaleY;
localX2 *= scaleX;
localY2 *= scaleY;
float cos = MathUtil::cosDeg(rotation);
float sin = MathUtil::sinDeg(rotation);
float localXCos = localX * cos + x;
float localXSin = localX * sin;
float localYCos = localY * cos + y;
float localYSin = localY * sin;
float localX2Cos = localX2 * cos + x;
float localX2Sin = localX2 * sin;
float localY2Cos = localY2 * cos + y;
float localY2Sin = localY2 * sin;
offset[BLX] = localXCos - localYSin;
offset[BLY] = localYCos + localXSin;
offset[ULX] = localXCos - localY2Sin;
offset[ULY] = localY2Cos + localXSin;
offset[URX] = localX2Cos - localY2Sin;
offset[URY] = localY2Cos + localX2Sin;
offset[BRX] = localX2Cos - localYSin;
offset[BRY] = localYCos + localX2Sin;
if (region == NULL) {
uvs[BLX] = 0;
uvs[BLY] = 0;
uvs[ULX] = 0;
uvs[ULY] = 1;
uvs[URX] = 1;
uvs[URY] = 1;
uvs[BRX] = 1;
uvs[BRY] = 0;
} else {
uvs[BLX] = region->_u2;
uvs[ULY] = region->_v2;
uvs[URX] = region->_u;
uvs[BRY] = region->_v;
if (rotated) {
uvs[BLY] = region->_v;
uvs[ULX] = region->_u2;
uvs[URY] = region->_v2;
uvs[BRX] = region->_u;
} else {
uvs[BLY] = region->_v2;
uvs[ULX] = region->_u;
uvs[URY] = region->_v;
uvs[BRX] = region->_u2;
}
}
}

View File

@ -1,45 +0,0 @@
/******************************************************************************
* 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 <spine/RotateTimeline.h>
#include <spine/BoneLocal.h>
using namespace spine;
RTTI_IMPL(RotateTimeline, BoneTimeline1)
RotateTimeline::RotateTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline1(frameCount, bezierCount, boneIndex, Property_Rotate) {
}
void RotateTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
SP_UNUSED(out);
pose._rotation = getRelativeValue(time, alpha, fromSetup, add, pose._rotation, setup._rotation);
}

View File

@ -1,129 +0,0 @@
/******************************************************************************
* 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 <spine/ScaleTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(ScaleTimeline, BoneTimeline2)
ScaleTimeline::ScaleTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline2(frameCount, bezierCount, boneIndex, Property_ScaleX, Property_ScaleY) {
}
void ScaleTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
if (time < _frames[0]) {
if (fromSetup) {
pose._scaleX = setup._scaleX;
pose._scaleY = setup._scaleY;
}
return;
}
float x, y;
int i = Animation::search(_frames, time, BoneTimeline2::ENTRIES);
int curveType = (int) _curves[i / BoneTimeline2::ENTRIES];
switch (curveType) {
case CurveTimeline::LINEAR: {
float before = _frames[i];
x = _frames[i + BoneTimeline2::VALUE1];
y = _frames[i + BoneTimeline2::VALUE2];
float t = (time - before) / (_frames[i + BoneTimeline2::ENTRIES] - before);
x += (_frames[i + BoneTimeline2::ENTRIES + BoneTimeline2::VALUE1] - x) * t;
y += (_frames[i + BoneTimeline2::ENTRIES + BoneTimeline2::VALUE2] - y) * t;
break;
}
case CurveTimeline::STEPPED: {
x = _frames[i + BoneTimeline2::VALUE1];
y = _frames[i + BoneTimeline2::VALUE2];
break;
}
default: {
x = getBezierValue(time, i, BoneTimeline2::VALUE1, curveType - BoneTimeline2::BEZIER);
y = getBezierValue(time, i, BoneTimeline2::VALUE2, curveType + BoneTimeline2::BEZIER_SIZE - BoneTimeline2::BEZIER);
}
}
x *= setup._scaleX;
y *= setup._scaleY;
if (alpha == 1 && !add) {
pose._scaleX = x;
pose._scaleY = y;
} else {
float bx, by;
if (fromSetup) {
bx = setup._scaleX;
by = setup._scaleY;
} else {
bx = pose._scaleX;
by = pose._scaleY;
}
if (add) {
pose._scaleX = bx + (x - setup._scaleX) * alpha;
pose._scaleY = by + (y - setup._scaleY) * alpha;
} else if (out) {
pose._scaleX = bx + (MathUtil::abs(x) * MathUtil::sign(bx) - bx) * alpha;
pose._scaleY = by + (MathUtil::abs(y) * MathUtil::sign(by) - by) * alpha;
} else {
bx = MathUtil::abs(bx) * MathUtil::sign(x);
by = MathUtil::abs(by) * MathUtil::sign(y);
pose._scaleX = bx + (x - bx) * alpha;
pose._scaleY = by + (y - by) * alpha;
}
}
}
RTTI_IMPL(ScaleXTimeline, BoneTimeline1)
ScaleXTimeline::ScaleXTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ScaleX) {
}
void ScaleXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
pose._scaleX = getScaleValue(time, alpha, fromSetup, add, out, pose._scaleX, setup._scaleX);
}
RTTI_IMPL(ScaleYTimeline, BoneTimeline1)
ScaleYTimeline::ScaleYTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ScaleY) {
}
void ScaleYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
pose._scaleY = getScaleValue(time, alpha, fromSetup, add, out, pose._scaleY, setup._scaleY);
}

View File

@ -1,110 +0,0 @@
/******************************************************************************
* 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 <spine/Sequence.h>
#include <spine/MeshAttachment.h>
#include <spine/RegionAttachment.h>
#include <spine/SlotPose.h>
using namespace spine;
int Sequence::_nextID = 0;
Sequence::Sequence(int count, bool pathSuffix)
: _id(nextID()), _regions(count), _pathSuffix(pathSuffix), _uvs(), _offsets(), _start(0), _digits(0), _setupIndex(0) {
_regions.setSize(count, NULL);
}
Sequence::Sequence(const Sequence &other)
: _id(nextID()), _regions(other._regions), _pathSuffix(other._pathSuffix), _uvs(other._uvs), _offsets(other._offsets), _start(other._start),
_digits(other._digits), _setupIndex(other._setupIndex) {
}
Sequence::~Sequence() {
}
void Sequence::update(RegionAttachment &attachment) {
int regionCount = (int) _regions.size();
Array<float> empty;
_uvs.setSize(regionCount, empty);
_offsets.setSize(regionCount, empty);
for (int i = 0; i < regionCount; i++) {
_uvs[i].setSize(8, 0);
_offsets[i].setSize(8, 0);
RegionAttachment::computeUVs(_regions[i], attachment.getX(), attachment.getY(), attachment.getScaleX(), attachment.getScaleY(),
attachment.getRotation(), attachment.getWidth(), attachment.getHeight(), _offsets[i], _uvs[i]);
}
}
void Sequence::update(MeshAttachment &attachment) {
int regionCount = (int) _regions.size();
Array<float> empty;
_uvs.setSize(regionCount, empty);
_offsets.clear();
for (int i = 0; i < regionCount; i++) {
_uvs[i].setSize(attachment.getRegionUVs().size(), 0);
MeshAttachment::computeUVs(_regions[i], attachment.getRegionUVs(), _uvs[i]);
}
}
int Sequence::resolveIndex(SlotPose &pose) {
int index = pose.getSequenceIndex();
if (index == -1) index = _setupIndex;
if (index >= (int) _regions.size()) index = (int) _regions.size() - 1;
return index;
}
TextureRegion *Sequence::getRegion(int index) {
return _regions[index];
}
Array<float> &Sequence::getUVs(int index) {
return _uvs[index];
}
Array<float> &Sequence::getOffsets(int index) {
return _offsets[index];
}
String &Sequence::getPath(const String &basePath, int index) {
if (!_pathSuffix) {
_tmpPath = basePath;
return _tmpPath;
}
_tmpPath = basePath;
String frame;
frame.append(_start + index);
for (int i = _digits - (int) frame.length(); i > 0; i--) _tmpPath.append("0");
_tmpPath.append(frame);
return _tmpPath;
}
int Sequence::nextID() {
return _nextID++;
}

View File

@ -1,143 +0,0 @@
/******************************************************************************
* 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 <spine/SequenceTimeline.h>
#include <spine/Bone.h>
#include <spine/RegionAttachment.h>
#include <spine/MeshAttachment.h>
#include <spine/VertexAttachment.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Attachment.h>
#include <spine/Slot.h>
#include <spine/Animation.h>
#include <spine/MathUtil.h>
using namespace spine;
RTTI_IMPL_MULTI(SequenceTimeline, Timeline, SlotTimeline)
SequenceTimeline::SequenceTimeline(size_t frameCount, int slotIndex, Attachment &attachment)
: Timeline(frameCount, ENTRIES), SlotTimeline(), _slotIndex(slotIndex), _attachment((HasTextureRegion *) &attachment) {
_instant = true;
int sequenceId = 0;
if (attachment.getRTTI().instanceOf(RegionAttachment::rtti)) sequenceId = ((RegionAttachment *) &attachment)->getSequence().getId();
if (attachment.getRTTI().instanceOf(MeshAttachment::rtti)) sequenceId = ((MeshAttachment *) &attachment)->getSequence().getId();
PropertyId ids[] = {((PropertyId) Property_Sequence << 32) | ((slotIndex << 16 | sequenceId) & 0xffffffff)};
setPropertyIds(ids, 1);
}
SequenceTimeline::~SequenceTimeline() {
}
void SequenceTimeline::setFrame(int frame, float time, SequenceMode mode, int index, float delay) {
Array<float> &frames = this->_frames;
frame *= ENTRIES;
frames[frame] = time;
frames[frame + MODE] = mode | (index << 4);
frames[frame + DELAY] = delay;
}
int SequenceTimeline::getSlotIndex() {
return _slotIndex;
}
void SequenceTimeline::setSlotIndex(int inValue) {
_slotIndex = inValue;
}
void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(alpha);
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(add);
Slot *slot = skeleton.getSlots()[getSlotIndex()];
if (!slot->getBone().isActive()) return;
SlotPose &pose = appliedPose ? slot->getAppliedPose() : slot->getPose();
Attachment *slotAttachment = pose.getAttachment();
if (slotAttachment != (Attachment *) _attachment) {
if (slotAttachment == NULL || slotAttachment->getTimelineAttachment() != (Attachment *) _attachment) return;
}
Sequence *sequence = NULL;
if (((Attachment *) _attachment)->getRTTI().instanceOf(RegionAttachment::rtti)) sequence = &((RegionAttachment *) _attachment)->getSequence();
if (((Attachment *) _attachment)->getRTTI().instanceOf(MeshAttachment::rtti)) sequence = &((MeshAttachment *) _attachment)->getSequence();
if (!sequence) return;
if (out) {
if (fromSetup) pose.setSequenceIndex(-1);
return;
}
Array<float> &frames = this->_frames;
if (time < frames[0]) {
if (fromSetup) pose.setSequenceIndex(-1);
return;
}
int i = Animation::search(frames, time, ENTRIES);
float before = frames[i];
int modeAndIndex = (int) frames[i + MODE];
float delay = frames[i + DELAY];
int index = modeAndIndex >> 4, count = (int) sequence->getRegions().size();
int mode = modeAndIndex & 0xf;
if (mode != SequenceMode_hold) {
index += (int) (((time - before) / delay + 0.0001));
switch (mode) {
case SequenceMode_once:
index = MathUtil::min(count - 1, index);
break;
case SequenceMode_loop:
index %= count;
break;
case SequenceMode_pingpong: {
int n = (count << 1) - 2;
index = n == 0 ? 0 : index % n;
if (index >= count) index = n - index;
break;
}
case SequenceMode_onceReverse:
index = MathUtil::max(count - 1 - index, 0);
break;
case SequenceMode_loopReverse:
index = count - 1 - (index % count);
break;
case SequenceMode_pingpongReverse: {
int n = (count << 1) - 2;
index = n == 0 ? 0 : (index + count - 1) % n;
if (index >= count) index = n - index;
break;
}
}
}
pose.setSequenceIndex(index);
}

View File

@ -1,115 +0,0 @@
/******************************************************************************
* 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 <spine/ShearTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(ShearTimeline, BoneTimeline2)
ShearTimeline::ShearTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline2(frameCount, bezierCount, boneIndex, Property_ShearX, Property_ShearY) {
}
void ShearTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
SP_UNUSED(out);
if (time < _frames[0]) {
if (fromSetup) {
pose._shearX = setup._shearX;
pose._shearY = setup._shearY;
}
return;
}
float x, y;
int i = Animation::search(_frames, time, BoneTimeline2::ENTRIES);
int curveType = (int) _curves[i / BoneTimeline2::ENTRIES];
switch (curveType) {
case CurveTimeline::LINEAR: {
float before = _frames[i];
x = _frames[i + BoneTimeline2::VALUE1];
y = _frames[i + BoneTimeline2::VALUE2];
float t = (time - before) / (_frames[i + BoneTimeline2::ENTRIES] - before);
x += (_frames[i + BoneTimeline2::ENTRIES + BoneTimeline2::VALUE1] - x) * t;
y += (_frames[i + BoneTimeline2::ENTRIES + BoneTimeline2::VALUE2] - y) * t;
break;
}
case CurveTimeline::STEPPED: {
x = _frames[i + BoneTimeline2::VALUE1];
y = _frames[i + BoneTimeline2::VALUE2];
break;
}
default: {
x = getBezierValue(time, i, BoneTimeline2::VALUE1, curveType - BoneTimeline2::BEZIER);
y = getBezierValue(time, i, BoneTimeline2::VALUE2, curveType + BoneTimeline2::BEZIER_SIZE - BoneTimeline2::BEZIER);
}
}
if (fromSetup) {
pose._shearX = setup._shearX + x * alpha;
pose._shearY = setup._shearY + y * alpha;
} else if (add) {
pose._shearX += x * alpha;
pose._shearY += y * alpha;
} else {
pose._shearX += (setup._shearX + x - pose._shearX) * alpha;
pose._shearY += (setup._shearY + y - pose._shearY) * alpha;
}
}
RTTI_IMPL(ShearXTimeline, BoneTimeline1)
ShearXTimeline::ShearXTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ShearX) {
}
void ShearXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
SP_UNUSED(out);
pose._shearX = getRelativeValue(time, alpha, fromSetup, add, pose._shearX, setup._shearX);
}
RTTI_IMPL(ShearYTimeline, BoneTimeline1)
ShearYTimeline::ShearYTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline1(frameCount, bezierCount, boneIndex, Property_ShearY) {
}
void ShearYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
SP_UNUSED(out);
pose._shearY = getRelativeValue(time, alpha, fromSetup, add, pose._shearY, setup._shearY);
}

View File

@ -1,553 +0,0 @@
/******************************************************************************
* 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 <spine/Skeleton.h>
#include <spine/Attachment.h>
#include <spine/Bone.h>
#include <spine/BonePose.h>
#include <spine/IkConstraint.h>
#include <spine/PathConstraint.h>
#include <spine/PhysicsConstraint.h>
#include <spine/SkeletonData.h>
#include <spine/Skin.h>
#include <spine/Slider.h>
#include <spine/Slot.h>
#include <spine/TransformConstraint.h>
#include <spine/BoneData.h>
#include <spine/ClippingAttachment.h>
#include <spine/IkConstraintData.h>
#include <spine/MeshAttachment.h>
#include <spine/PathAttachment.h>
#include <spine/PathConstraintData.h>
#include <spine/PhysicsConstraintData.h>
#include <spine/RegionAttachment.h>
#include <spine/SkeletonClipping.h>
#include <spine/SlotData.h>
#include <spine/TransformConstraintData.h>
#include <spine/ArrayUtils.h>
#include <float.h>
using namespace spine;
Skeleton::Skeleton(SkeletonData &skeletonData)
: _data(skeletonData), _skin(NULL), _color(1, 1, 1, 1), _x(0), _y(0), _scaleX(1), _scaleY(1), _windX(1), _windY(0), _gravityX(0), _gravityY(1),
_time(0), _update(0) {
_bones.ensureCapacity(_data.getBones().size());
for (size_t i = 0; i < _data.getBones().size(); ++i) {
BoneData *data = _data.getBones()[i];
Bone *bone;
if (data->getParent() == NULL) {
bone = new (__FILE__, __LINE__) Bone(*data, NULL);
} else {
Bone *parent = _bones[data->getParent()->getIndex()];
bone = new (__FILE__, __LINE__) Bone(*data, parent);
parent->getChildren().add(bone);
}
_bones.add(bone);
}
_slots.ensureCapacity(_data.getSlots().size());
_drawOrder.ensureCapacity(_data.getSlots().size());
for (size_t i = 0; i < _data.getSlots().size(); ++i) {
SlotData *data = _data.getSlots()[i];
Slot *slot = new (__FILE__, __LINE__) Slot(*data, *this);
_slots.add(slot);
_drawOrder.add(slot);
}
_physics.ensureCapacity(8);
_constraints.ensureCapacity(_data.getConstraints().size());
for (size_t i = 0; i < _data.getConstraints().size(); ++i) {
ConstraintData *constraintData = _data.getConstraints()[i];
Constraint *constraint = &constraintData->create(*this);
if (constraint->getRTTI().instanceOf(PhysicsConstraint::rtti)) {
_physics.add(static_cast<PhysicsConstraint *>(constraint));
}
_constraints.add(constraint);
}
updateCache();
}
Skeleton::~Skeleton() {
ArrayUtils::deleteElements(_bones);
ArrayUtils::deleteElements(_slots);
ArrayUtils::deleteElements(_constraints);
}
void Skeleton::updateCache() {
_updateCache.clear();
_resetCache.clear();
Slot **slots = _slots.buffer();
for (size_t i = 0, n = _slots.size(); i < n; i++) {
slots[i]->pose();
}
size_t boneCount = _bones.size();
Bone **bones = _bones.buffer();
for (size_t i = 0; i < boneCount; i++) {
Bone *bone = bones[i];
bone->_sorted = bone->_data.getSkinRequired();
bone->_active = !bone->_sorted;
bone->pose();
}
if (_skin) {
Array<BoneData *> &skinBones = _skin->getBones();
for (size_t i = 0, n = skinBones.size(); i < n; i++) {
Bone *bone = _bones[skinBones[i]->getIndex()];
do {
bone->_sorted = false;
bone->_active = true;
bone = bone->_parent;
} while (bone);
}
}
Constraint **constraints = _constraints.buffer();
size_t n = _constraints.size();
for (size_t i = 0; i < n; i++) {
constraints[i]->pose();
}
for (size_t i = 0; i < n; i++) {
Constraint *constraint = constraints[i];
constraint->_active = constraint->isSourceActive() &&
((!constraint->getData().getSkinRequired()) || (_skin && _skin->_constraints.contains(&constraint->getData())));
if (constraint->_active) constraint->sort(*this);
}
for (size_t i = 0; i < boneCount; i++) {
sortBone(bones[i]);
}
Update **updateCache = _updateCache.buffer();
n = _updateCache.size();
for (size_t i = 0; i < n; i++) {
const RTTI &rtti = updateCache[i]->getRTTI();
if (rtti.instanceOf(Bone::rtti)) {
Bone *bone = (Bone *) (updateCache[i]);
updateCache[i] = bone->_applied;
}
}
}
void Skeleton::printUpdateCache() {
for (size_t i = 0; i < _updateCache.size(); i++) {
Update *updatable = _updateCache[i];
if (updatable->getRTTI().isExactly(Bone::rtti)) {
printf("bone %s\n", ((Bone *) updatable)->getData().getName().buffer());
} else if (updatable->getRTTI().isExactly(TransformConstraint::rtti)) {
printf("transform constraint %s\n", ((TransformConstraint *) updatable)->getData().getName().buffer());
} else if (updatable->getRTTI().isExactly(IkConstraint::rtti)) {
printf("ik constraint %s\n", ((IkConstraint *) updatable)->getData().getName().buffer());
} else if (updatable->getRTTI().isExactly(PathConstraint::rtti)) {
printf("path constraint %s\n", ((PathConstraint *) updatable)->getData().getName().buffer());
} else if (updatable->getRTTI().isExactly(PhysicsConstraint::rtti)) {
printf("physics constraint %s\n", ((PhysicsConstraint *) updatable)->getData().getName().buffer());
} else if (updatable->getRTTI().isExactly(Slider::rtti)) {
printf("slider %s\n", ((Slider *) updatable)->getData().getName().buffer());
}
}
}
void Skeleton::constrained(Posed &object) {
if (object.isPoseEqualToApplied()) {
object.constrained();
_resetCache.add(&object);
}
}
void Skeleton::sortBone(Bone *bone) {
if (bone->_sorted || !bone->_active) return;
Bone *parent = bone->_parent;
if (parent != NULL) sortBone(parent);
bone->_sorted = true;
_updateCache.add((Update *) bone);
}
void Skeleton::sortReset(Array<Bone *> &bones) {
Bone **items = bones.buffer();
for (size_t i = 0, n = bones.size(); i < n; i++) {
Bone *bone = items[i];
if (bone->_active) {
if (bone->_sorted) sortReset(bone->getChildren());
bone->_sorted = false;
}
}
}
void Skeleton::updateWorldTransform(Physics physics) {
_update++;
Posed **resetCache = _resetCache.buffer();
for (size_t i = 0, n = _resetCache.size(); i < n; i++) {
resetCache[i]->resetConstrained();
}
Update **updateCache = _updateCache.buffer();
for (size_t i = 0, n = _updateCache.size(); i < n; i++) {
updateCache[i]->update(*this, physics);
}
}
void Skeleton::setupPose() {
setupPoseBones();
setupPoseSlots();
}
void Skeleton::setupPoseBones() {
Bone **bones = _bones.buffer();
for (size_t i = 0, n = _bones.size(); i < n; ++i) {
bones[i]->setupPose();
}
Constraint **constraints = _constraints.buffer();
for (size_t i = 0, n = _constraints.size(); i < n; ++i) {
constraints[i]->setupPose();
}
}
void Skeleton::setupPoseSlots() {
Slot **slots = _slots.buffer();
size_t n = _slots.size();
_drawOrder.clear();
_drawOrder.setSize(n, 0);
for (size_t i = 0; i < n; ++i) {
_drawOrder[i] = _slots[i];
}
for (size_t i = 0; i < n; ++i) {
slots[i]->setupPose();
}
}
SkeletonData &Skeleton::getData() {
return _data;
}
Array<Bone *> &Skeleton::getBones() {
return _bones;
}
Array<Update *> &Skeleton::getUpdateCache() {
return _updateCache;
}
Bone *Skeleton::getRootBone() {
return _bones.size() == 0 ? NULL : _bones[0];
}
Bone *Skeleton::findBone(const String &boneName) {
if (boneName.isEmpty()) return NULL;
Bone **bones = _bones.buffer();
for (size_t i = 0, n = _bones.size(); i < n; i++) {
if (bones[i]->_data.getName() == boneName) return bones[i];
}
return NULL;
}
Array<Slot *> &Skeleton::getSlots() {
return _slots;
}
Slot *Skeleton::findSlot(const String &slotName) {
if (slotName.isEmpty()) return NULL;
Slot **slots = _slots.buffer();
for (size_t i = 0, n = _slots.size(); i < n; i++) {
if (slots[i]->_data.getName() == slotName) return slots[i];
}
return NULL;
}
Array<Slot *> &Skeleton::getDrawOrder() {
return _drawOrder;
}
Skin *Skeleton::getSkin() {
return _skin;
}
void Skeleton::setSkin(const String &skinName) {
Skin *skin = skinName.isEmpty() ? NULL : _data.findSkin(skinName);
if (skin == NULL) return;
setSkin(skin);
}
void Skeleton::setSkin(Skin *newSkin) {
if (_skin == newSkin) return;
if (newSkin != NULL) {
if (_skin != NULL) {
newSkin->attachAll(*this, *_skin);
} else {
Slot **slots = _slots.buffer();
for (size_t i = 0, n = _slots.size(); i < n; ++i) {
Slot *slot = slots[i];
const String &name = slot->_data.getAttachmentName();
if (name.length() > 0) {
Attachment *attachment = newSkin->getAttachment(i, name);
if (attachment != NULL) {
slot->_pose.setAttachment(attachment);
}
}
}
}
}
_skin = newSkin;
updateCache();
}
Attachment *Skeleton::getAttachment(const String &slotName, const String &attachmentName) {
SlotData *slot = _data.findSlot(slotName);
if (slot == NULL) return NULL;
return getAttachment(slot->getIndex(), attachmentName);
}
Attachment *Skeleton::getAttachment(int slotIndex, const String &attachmentName) {
if (attachmentName.isEmpty()) return NULL;
if (_skin != NULL) {
Attachment *attachment = _skin->getAttachment(slotIndex, attachmentName);
if (attachment != NULL) return attachment;
}
if (_data.getDefaultSkin() != NULL) return _data.getDefaultSkin()->getAttachment(slotIndex, attachmentName);
return NULL;
}
void Skeleton::setAttachment(const String &slotName, const String &attachmentName) {
if (slotName.isEmpty()) return;
Slot *slot = findSlot(slotName);
if (slot == NULL) return;
Attachment *attachment = NULL;
if (!attachmentName.isEmpty()) {
attachment = getAttachment(slot->_data.getIndex(), attachmentName);
if (attachment == NULL) return;
}
slot->_pose.setAttachment(attachment);
}
Array<Constraint *> &Skeleton::getConstraints() {
return _constraints;
}
Array<PhysicsConstraint *> &Skeleton::getPhysicsConstraints() {
return _physics;
}
void Skeleton::getBounds(float &outX, float &outY, float &outWidth, float &outHeight) {
Array<float> outVertexBuffer;
getBounds(outX, outY, outWidth, outHeight, outVertexBuffer, NULL);
}
void Skeleton::getBounds(float &outX, float &outY, float &outWidth, float &outHeight, Array<float> &outVertexBuffer, SkeletonClipping *clipper) {
static unsigned short quadIndices[] = {0, 1, 2, 2, 3, 0};
float minX = FLT_MAX;
float minY = FLT_MAX;
float maxX = -FLT_MAX;
float maxY = -FLT_MAX;
Slot **drawOrder = _drawOrder.buffer();
for (size_t i = 0, n = _drawOrder.size(); i < n; ++i) {
Slot *slot = drawOrder[i];
if (!slot->_bone._active) continue;
size_t verticesLength = 0;
float *vertices = NULL;
unsigned short *triangles = NULL;
size_t trianglesLength = 0;
Attachment *attachment = slot->_pose.getAttachment();
if (attachment != NULL) {
if (attachment->getRTTI().instanceOf(RegionAttachment::rtti)) {
RegionAttachment *regionAttachment = static_cast<RegionAttachment *>(attachment);
verticesLength = 8;
outVertexBuffer.setSize(8, 0);
regionAttachment->computeWorldVertices(*slot, regionAttachment->getOffsets(slot->getAppliedPose()), outVertexBuffer, 0, 2);
vertices = outVertexBuffer.buffer();
triangles = quadIndices;
trianglesLength = 6;
} else if (attachment->getRTTI().instanceOf(MeshAttachment::rtti)) {
MeshAttachment *mesh = static_cast<MeshAttachment *>(attachment);
verticesLength = mesh->getWorldVerticesLength();
outVertexBuffer.setSize(verticesLength, 0);
mesh->computeWorldVertices(*this, *slot, 0, verticesLength, outVertexBuffer.buffer(), 0, 2);
vertices = outVertexBuffer.buffer();
triangles = mesh->getTriangles().buffer();
trianglesLength = mesh->getTriangles().size();
} else if (attachment->getRTTI().instanceOf(ClippingAttachment::rtti) && clipper != NULL) {
clipper->clipEnd(*slot);
clipper->clipStart(*this, *slot, static_cast<ClippingAttachment *>(attachment));
continue;
}
if (vertices != NULL) {
if (clipper != NULL && clipper->isClipping() && clipper->clipTriangles(vertices, triangles, trianglesLength)) {
vertices = clipper->getClippedVertices().buffer();
verticesLength = clipper->getClippedVertices().size();
}
for (size_t ii = 0; ii < verticesLength; ii += 2) {
float x = vertices[ii], y = vertices[ii + 1];
minX = MathUtil::min(minX, x);
minY = MathUtil::min(minY, y);
maxX = MathUtil::max(maxX, x);
maxY = MathUtil::max(maxY, y);
}
}
}
if (clipper != NULL) clipper->clipEnd(*slot);
}
if (clipper != NULL) clipper->clipEnd();
outX = minX;
outY = minY;
outWidth = maxX - minX;
outHeight = maxY - minY;
}
Color &Skeleton::getColor() {
return _color;
}
void Skeleton::setColor(Color &color) {
_color.set(color.r, color.g, color.b, color.a);
}
void Skeleton::setColor(float r, float g, float b, float a) {
_color.set(r, g, b, a);
}
float Skeleton::getScaleX() {
return _scaleX;
}
void Skeleton::setScaleX(float inValue) {
_scaleX = inValue;
}
float Skeleton::getScaleY() {
return _scaleY * (Bone::isYDown() ? -1 : 1);
}
void Skeleton::setScaleY(float inValue) {
_scaleY = inValue;
}
void Skeleton::setScale(float scaleX, float scaleY) {
_scaleX = scaleX;
_scaleY = scaleY;
}
float Skeleton::getX() {
return _x;
}
void Skeleton::setX(float inValue) {
_x = inValue;
}
float Skeleton::getY() {
return _y;
}
void Skeleton::setY(float inValue) {
_y = inValue;
}
void Skeleton::setPosition(float x, float y) {
_x = x;
_y = y;
}
void Skeleton::getPosition(float &x, float &y) {
x = _x;
y = _y;
}
float Skeleton::getWindX() {
return _windX;
}
void Skeleton::setWindX(float windX) {
_windX = windX;
}
float Skeleton::getWindY() {
return _windY;
}
void Skeleton::setWindY(float windY) {
_windY = windY;
}
float Skeleton::getGravityX() {
return _gravityX;
}
void Skeleton::setGravityX(float gravityX) {
_gravityX = gravityX;
}
float Skeleton::getGravityY() {
return _gravityY;
}
void Skeleton::setGravityY(float gravityY) {
_gravityY = gravityY;
}
void Skeleton::physicsTranslate(float x, float y) {
PhysicsConstraint **constraints = _physics.buffer();
for (size_t i = 0, n = _physics.size(); i < n; i++) {
constraints[i]->translate(x, y);
}
}
void Skeleton::physicsRotate(float x, float y, float degrees) {
PhysicsConstraint **constraints = _physics.buffer();
for (size_t i = 0, n = _physics.size(); i < n; i++) {
constraints[i]->rotate(x, y, degrees);
}
}
float Skeleton::getTime() {
return _time;
}
void Skeleton::setTime(float time) {
_time = time;
}
void Skeleton::update(float delta) {
_time += delta;
}

View File

@ -1,245 +0,0 @@
/******************************************************************************
* 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 <spine/SkeletonBounds.h>
#include <spine/Bone.h>
#include <spine/BoundingBoxAttachment.h>
#include <spine/Skeleton.h>
#include <spine/Slot.h>
#include <float.h>
using namespace spine;
SkeletonBounds::SkeletonBounds() : _minX(0), _minY(0), _maxX(0), _maxY(0) {
}
SkeletonBounds::~SkeletonBounds() {
for (size_t i = 0, n = _polygons.size(); i < n; i++) _polygonPool.free(_polygons[i]);
_polygons.clear();
}
void SkeletonBounds::update(Skeleton &skeleton, bool updateAabb) {
Array<Slot *> &slots = skeleton.getSlots();
size_t slotCount = slots.size();
_boundingBoxes.clear();
for (size_t i = 0, n = _polygons.size(); i < n; ++i) {
_polygonPool.free(_polygons[i]);
}
_polygons.clear();
for (size_t i = 0; i < slotCount; i++) {
Slot *slot = slots[i];
if (!slot->getBone().isActive()) continue;
Attachment *attachment = slot->_applied->getAttachment();
if (attachment == NULL || !attachment->getRTTI().instanceOf(BoundingBoxAttachment::rtti)) continue;
BoundingBoxAttachment *boundingBox = static_cast<BoundingBoxAttachment *>(attachment);
_boundingBoxes.add(boundingBox);
Polygon *polygonP = _polygonPool.obtain();
_polygons.add(polygonP);
Polygon &polygon = *polygonP;
size_t count = boundingBox->getWorldVerticesLength();
polygon._count = (int) count;
if (polygon._vertices.size() < count) {
polygon._vertices.setSize(count, 0);
}
boundingBox->computeWorldVertices(skeleton, *slot, 0, count, polygon._vertices, 0, 2);
}
if (updateAabb)
aabbCompute();
else {
_minX = FLT_MIN;
_minY = FLT_MIN;
_maxX = FLT_MAX;
_maxY = FLT_MAX;
}
}
bool SkeletonBounds::aabbContainsPoint(float x, float y) {
return x >= _minX && x <= _maxX && y >= _minY && y <= _maxY;
}
bool SkeletonBounds::aabbIntersectsSegment(float x1, float y1, float x2, float y2) {
float minX = _minX;
float minY = _minY;
float maxX = _maxX;
float maxY = _maxY;
if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) {
return false;
}
float m = (y2 - y1) / (x2 - x1);
float y = m * (minX - x1) + y1;
if (y > minY && y < maxY) return true;
y = m * (maxX - x1) + y1;
if (y > minY && y < maxY) return true;
float x = (minY - y1) / m + x1;
if (x > minX && x < maxX) return true;
x = (maxY - y1) / m + x1;
if (x > minX && x < maxX) return true;
return false;
}
bool SkeletonBounds::aabbIntersectsSkeleton(SkeletonBounds &bounds) {
return _minX < bounds._maxX && _maxX > bounds._minX && _minY < bounds._maxY && _maxY > bounds._minY;
}
bool SkeletonBounds::containsPoint(Polygon &polygon, float x, float y) {
Array<float> &vertices = polygon._vertices;
int nn = polygon._count;
int prevIndex = nn - 2;
bool inside = false;
for (int ii = 0; ii < nn; ii += 2) {
float vertexY = vertices[ii + 1];
float prevY = vertices[prevIndex + 1];
if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) {
float vertexX = vertices[ii];
if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) {
inside = !inside;
}
}
prevIndex = ii;
}
return inside;
}
BoundingBoxAttachment *SkeletonBounds::containsPoint(float x, float y) {
for (size_t i = 0, n = _polygons.size(); i < n; ++i)
if (containsPoint(*_polygons[i], x, y)) return _boundingBoxes[i];
return NULL;
}
BoundingBoxAttachment *SkeletonBounds::intersectsSegment(float x1, float y1, float x2, float y2) {
for (size_t i = 0, n = _polygons.size(); i < n; ++i)
if (intersectsSegment(*_polygons[i], x1, y1, x2, y2)) return _boundingBoxes[i];
return NULL;
}
bool SkeletonBounds::intersectsSegment(Polygon &polygon, float x1, float y1, float x2, float y2) {
Array<float> &vertices = polygon._vertices;
size_t nn = polygon._count;
float width12 = x1 - x2, height12 = y1 - y2;
float det1 = x1 * y2 - y1 * x2;
float x3 = vertices[nn - 2], y3 = vertices[nn - 1];
for (size_t ii = 0; ii < nn; ii += 2) {
float x4 = vertices[ii], y4 = vertices[ii + 1];
float det2 = x3 * y4 - y3 * x4;
float width34 = x3 - x4, height34 = y3 - y4;
float det3 = width12 * height34 - height12 * width34;
float x = (det1 * width34 - width12 * det2) / det3;
if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) {
float y = (det1 * height34 - height12 * det2) / det3;
if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) {
return true;
}
}
x3 = x4;
y3 = y4;
}
return false;
}
spine::Polygon *SkeletonBounds::getPolygon(BoundingBoxAttachment *attachment) {
int index = _boundingBoxes.indexOf(attachment);
return index == -1 ? NULL : _polygons[index];
}
BoundingBoxAttachment *SkeletonBounds::getBoundingBox(spine::Polygon *polygon) {
int index = _polygons.indexOf(polygon);
return index == -1 ? NULL : _boundingBoxes[index];
}
Array<spine::Polygon *> &SkeletonBounds::getPolygons() {
return _polygons;
}
Array<BoundingBoxAttachment *> &SkeletonBounds::getBoundingBoxes() {
return _boundingBoxes;
}
float SkeletonBounds::getMinX() {
return _minX;
}
float SkeletonBounds::getMinY() {
return _minY;
}
float SkeletonBounds::getMaxX() {
return _maxX;
}
float SkeletonBounds::getMaxY() {
return _maxY;
}
float SkeletonBounds::getWidth() {
return _maxX - _minX;
}
float SkeletonBounds::getHeight() {
return _maxY - _minY;
}
void SkeletonBounds::aabbCompute() {
float minX = FLT_MAX;
float minY = FLT_MAX;
float maxX = FLT_MIN;
float maxY = FLT_MIN;
for (size_t i = 0, n = _polygons.size(); i < n; ++i) {
Polygon *polygon = _polygons[i];
Array<float> &vertices = polygon->_vertices;
for (int ii = 0, nn = polygon->_count; ii < nn; ii += 2) {
float x = vertices[ii];
float y = vertices[ii + 1];
minX = MathUtil::min(minX, x);
minY = MathUtil::min(minY, y);
maxX = MathUtil::max(maxX, x);
maxY = MathUtil::max(maxY, y);
}
}
_minX = minX;
_minY = minY;
_maxX = maxX;
_maxY = maxY;
}

View File

@ -1,397 +0,0 @@
/******************************************************************************
* 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 <spine/SkeletonClipping.h>
#include <spine/ClippingAttachment.h>
#include <spine/Slot.h>
using namespace spine;
SkeletonClipping::SkeletonClipping() : _clipAttachment(NULL) {
_clipOutput.ensureCapacity(128);
_clippedVertices.ensureCapacity(128);
_clippedTriangles.ensureCapacity(128);
_clippedUVs.ensureCapacity(128);
}
size_t SkeletonClipping::clipStart(Skeleton &skeleton, Slot &slot, ClippingAttachment *clip) {
if (_clipAttachment != NULL) {
return 0;
}
_clipAttachment = clip;
int n = (int) clip->getWorldVerticesLength();
if (n < 6) {
return 0;
}
_clippingPolygon.setSize(n, 0);
clip->computeWorldVertices(skeleton, slot, 0, n, _clippingPolygon.buffer(), 0, 2);
makeClockwise(_clippingPolygon);
_clippingPolygons = &_triangulator.decompose(_clippingPolygon, _triangulator.triangulate(_clippingPolygon));
for (size_t i = 0; i < _clippingPolygons->size(); ++i) {
Array<float> *polygonP = (*_clippingPolygons)[i];
Array<float> &polygon = *polygonP;
makeClockwise(polygon);
polygon.add(polygon[0]);
polygon.add(polygon[1]);
}
return (*_clippingPolygons).size();
}
void SkeletonClipping::clipEnd(Slot &slot) {
if (_clipAttachment != NULL && _clipAttachment->_endSlot == &slot._data) {
clipEnd();
}
}
void SkeletonClipping::clipEnd() {
if (_clipAttachment == NULL) return;
_clipAttachment = NULL;
_clippingPolygons = NULL;
_clippedVertices.clear();
_clippedUVs.clear();
_clippedTriangles.clear();
_clippingPolygon.clear();
}
bool SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength) {
Array<float> &clipOutput = _clipOutput;
Array<float> &clippedVertices = _clippedVertices;
Array<unsigned short> &clippedTriangles = _clippedTriangles;
Array<Array<float> *> &polygons = *_clippingPolygons;
size_t polygonsCount = (*_clippingPolygons).size();
size_t index = 0;
clippedVertices.clear();
_clippedUVs.clear();
clippedTriangles.clear();
bool clipped = false;
int stride = 2;
for (size_t i = 0; i < trianglesLength; i += 3) {
int vertexOffset = triangles[i] * stride;
float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
vertexOffset = triangles[i + 1] * stride;
float x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1];
vertexOffset = triangles[i + 2] * stride;
float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1];
for (size_t p = 0; p < polygonsCount; p++) {
size_t s = clippedVertices.size();
if (clip(x1, y1, x2, y2, x3, y3, &(*polygons[p]), &clipOutput)) {
size_t clipOutputLength = clipOutput.size();
if (clipOutputLength == 0) continue;
clipped = true;
size_t clipOutputCount = clipOutputLength >> 1;
clippedVertices.setSize(s + clipOutputCount * 2, 0);
for (size_t ii = 0; ii < clipOutputLength; ii += 2) {
float x = clipOutput[ii], y = clipOutput[ii + 1];
clippedVertices[s] = x;
clippedVertices[s + 1] = y;
s += 2;
}
s = clippedTriangles.size();
clippedTriangles.setSize(s + 3 * (clipOutputCount - 2), 0);
clipOutputCount--;
for (size_t ii = 1; ii < clipOutputCount; ii++) {
clippedTriangles[s] = (unsigned short) (index);
clippedTriangles[s + 1] = (unsigned short) (index + ii);
clippedTriangles[s + 2] = (unsigned short) (index + ii + 1);
s += 3;
}
index += clipOutputCount + 1;
} else {
clippedVertices.setSize(s + 3 * 2, 0);
clippedVertices[s] = x1;
clippedVertices[s + 1] = y1;
clippedVertices[s + 2] = x2;
clippedVertices[s + 3] = y2;
clippedVertices[s + 4] = x3;
clippedVertices[s + 5] = y3;
s = clippedTriangles.size();
clippedTriangles.setSize(s + 3, 0);
clippedTriangles[s] = (unsigned short) index;
clippedTriangles[s + 1] = (unsigned short) (index + 1);
clippedTriangles[s + 2] = (unsigned short) (index + 2);
index += 3;
break;
}
}
}
return clipped;
}
bool SkeletonClipping::clipTriangles(Array<float> &vertices, Array<unsigned short> &triangles, Array<float> &uvs, size_t stride) {
return clipTriangles(vertices.buffer(), triangles.buffer(), triangles.size(), uvs.buffer(), stride);
}
bool SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength, float *uvs, size_t stride) {
Array<float> &clipOutput = _clipOutput;
Array<float> &clippedVertices = _clippedVertices;
Array<unsigned short> &clippedTriangles = _clippedTriangles;
Array<Array<float> *> &polygons = *_clippingPolygons;
size_t polygonsCount = (*_clippingPolygons).size();
size_t index = 0;
clippedVertices.clear();
_clippedUVs.clear();
clippedTriangles.clear();
bool clipped = false;
for (size_t i = 0; i < trianglesLength; i += 3) {
int vertexOffset = triangles[i] * (int) stride;
float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
float u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1];
vertexOffset = triangles[i + 1] * (int) stride;
float x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1];
float u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1];
vertexOffset = triangles[i + 2] * (int) stride;
float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1];
float u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1];
for (size_t p = 0; p < polygonsCount; p++) {
size_t s = clippedVertices.size();
if (clip(x1, y1, x2, y2, x3, y3, &(*polygons[p]), &clipOutput)) {
size_t clipOutputLength = clipOutput.size();
if (clipOutputLength == 0) continue;
clipped = true;
float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
float d = 1 / (d0 * d2 + d1 * (y1 - y3));
size_t clipOutputCount = clipOutputLength >> 1;
clippedVertices.setSize(s + clipOutputCount * 2, 0);
_clippedUVs.setSize(s + clipOutputCount * 2, 0);
for (size_t ii = 0; ii < clipOutputLength; ii += 2) {
float x = clipOutput[ii], y = clipOutput[ii + 1];
clippedVertices[s] = x;
clippedVertices[s + 1] = y;
float c0 = x - x3, c1 = y - y3;
float a = (d0 * c0 + d1 * c1) * d;
float b = (d4 * c0 + d2 * c1) * d;
float c = 1 - a - b;
_clippedUVs[s] = u1 * a + u2 * b + u3 * c;
_clippedUVs[s + 1] = v1 * a + v2 * b + v3 * c;
s += 2;
}
s = clippedTriangles.size();
clippedTriangles.setSize(s + 3 * (clipOutputCount - 2), 0);
clipOutputCount--;
for (size_t ii = 1; ii < clipOutputCount; ii++) {
clippedTriangles[s] = (unsigned short) (index);
clippedTriangles[s + 1] = (unsigned short) (index + ii);
clippedTriangles[s + 2] = (unsigned short) (index + ii + 1);
s += 3;
}
index += clipOutputCount + 1;
} else {
clippedVertices.setSize(s + 3 * 2, 0);
_clippedUVs.setSize(s + 3 * 2, 0);
clippedVertices[s] = x1;
clippedVertices[s + 1] = y1;
clippedVertices[s + 2] = x2;
clippedVertices[s + 3] = y2;
clippedVertices[s + 4] = x3;
clippedVertices[s + 5] = y3;
_clippedUVs[s] = u1;
_clippedUVs[s + 1] = v1;
_clippedUVs[s + 2] = u2;
_clippedUVs[s + 3] = v2;
_clippedUVs[s + 4] = u3;
_clippedUVs[s + 5] = v3;
s = clippedTriangles.size();
clippedTriangles.setSize(s + 3, 0);
clippedTriangles[s] = (unsigned short) index;
clippedTriangles[s + 1] = (unsigned short) (index + 1);
clippedTriangles[s + 2] = (unsigned short) (index + 2);
index += 3;
break;
}
}
}
return clipped;
}
bool SkeletonClipping::isClipping() {
return _clipAttachment != NULL;
}
Array<float> &SkeletonClipping::getClippedVertices() {
return _clippedVertices;
}
Array<unsigned short> &SkeletonClipping::getClippedTriangles() {
return _clippedTriangles;
}
Array<float> &SkeletonClipping::getClippedUVs() {
return _clippedUVs;
}
bool SkeletonClipping::clip(float x1, float y1, float x2, float y2, float x3, float y3, Array<float> *clippingArea, Array<float> *output) {
Array<float> *originalOutput = output;
bool clipped = false;
// Avoid copy at the end.
Array<float> *input;
if (clippingArea->size() % 4 >= 2) {
input = output;
output = &_scratch;
} else
input = &_scratch;
input->clear();
input->add(x1);
input->add(y1);
input->add(x2);
input->add(y2);
input->add(x3);
input->add(y3);
input->add(x1);
input->add(y1);
output->clear();
size_t clippingVerticesLast = clippingArea->size() - 4;
Array<float> &clippingVertices = *clippingArea;
for (size_t i = 0;; i += 2) {
float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1];
float ex = edgeX - clippingVertices[i + 2], ey = edgeY - clippingVertices[i + 3];
size_t outputStart = output->size();
Array<float> &inputVertices = *input;
for (size_t ii = 0, nn = input->size() - 2; ii < nn;) {
float inputX = inputVertices[ii], inputY = inputVertices[ii + 1];
ii += 2;
float inputX2 = inputVertices[ii], inputY2 = inputVertices[ii + 1];
bool s2 = ey * (edgeX - inputX2) > ex * (edgeY - inputY2);
float s1 = ey * (edgeX - inputX) - ex * (edgeY - inputY);
if (s1 > 0) {
if (s2) {// v1 inside, v2 inside
output->add(inputX2);
output->add(inputY2);
continue;
}
// v1 inside, v2 outside
float ix = inputX2 - inputX, iy = inputY2 - inputY, t = s1 / (ix * ey - iy * ex);
if (t >= 0 && t <= 1) {
output->add(inputX + ix * t);
output->add(inputY + iy * t);
} else {
output->add(inputX2);
output->add(inputY2);
continue;
}
} else if (s2) {// v1 outside, v2 inside
float ix = inputX2 - inputX, iy = inputY2 - inputY, t = s1 / (ix * ey - iy * ex);
if (t >= 0 && t <= 1) {
output->add(inputX + ix * t);
output->add(inputY + iy * t);
output->add(inputX2);
output->add(inputY2);
} else {
output->add(inputX2);
output->add(inputY2);
continue;
}
}
clipped = true;
}
if (outputStart == output->size()) {
// All edges outside.
originalOutput->clear();
return true;
}
output->add((*output)[0]);
output->add((*output)[1]);
if (i == clippingVerticesLast) {
break;
}
Array<float> *temp = output;
output = input;
output->clear();
input = temp;
}
if (originalOutput != output) {
originalOutput->clear();
for (size_t i = 0, n = output->size() - 2; i < n; ++i) originalOutput->add((*output)[i]);
} else
originalOutput->setSize(originalOutput->size() - 2, 0);
if (originalOutput->size() < 6) {
originalOutput->clear();
return false;
}
return clipped;
}
void SkeletonClipping::makeClockwise(Array<float> &polygon) {
size_t verticeslength = polygon.size();
float area = polygon[verticeslength - 2] * polygon[1] - polygon[0] * polygon[verticeslength - 1];
float p1x, p1y, p2x, p2y;
for (size_t i = 0, n = verticeslength - 3; i < n; i += 2) {
p1x = polygon[i];
p1y = polygon[i + 1];
p2x = polygon[i + 2];
p2y = polygon[i + 3];
area += p1x * p2y - p2x * p1y;
}
if (area < 0) return;
for (size_t i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) {
float x = polygon[i], y = polygon[i + 1];
int other = (int) (lastX - i);
polygon[i] = polygon[other];
polygon[i + 1] = polygon[other + 1];
polygon[other] = x;
polygon[other + 1] = y;
}
}

View File

@ -1,218 +0,0 @@
/******************************************************************************
* 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 <spine/SkeletonData.h>
#include <spine/Animation.h>
#include <spine/BoneData.h>
#include <spine/ConstraintData.h>
#include <spine/EventData.h>
#include <spine/IkConstraintData.h>
#include <spine/PathConstraintData.h>
#include <spine/PhysicsConstraintData.h>
#include <spine/Skin.h>
#include <spine/SlotData.h>
#include <spine/TransformConstraintData.h>
#include <spine/SliderData.h>
#include <spine/ArrayUtils.h>
using namespace spine;
SkeletonData::SkeletonData()
: _name(), _defaultSkin(NULL), _x(0), _y(0), _width(0), _height(0), _referenceScale(100), _version(), _hash(), _fps(30), _imagesPath(),
_audioPath() {
}
SkeletonData::~SkeletonData() {
ArrayUtils::deleteElements(_bones);
ArrayUtils::deleteElements(_slots);
ArrayUtils::deleteElements(_skins);
_defaultSkin = NULL;
ArrayUtils::deleteElements(_events);
ArrayUtils::deleteElements(_animations);
ArrayUtils::deleteElements(_constraints);
for (size_t i = 0; i < _strings.size(); i++) {
SpineExtension::free(_strings[i], __FILE__, __LINE__);
}
}
BoneData *SkeletonData::findBone(const String &boneName) {
return ArrayUtils::findWithName(_bones, boneName);
}
SlotData *SkeletonData::findSlot(const String &slotName) {
return ArrayUtils::findWithName(_slots, slotName);
}
Skin *SkeletonData::findSkin(const String &skinName) {
return ArrayUtils::findWithName(_skins, skinName);
}
EventData *SkeletonData::findEvent(const String &eventDataName) {
return ArrayUtils::findWithName(_events, eventDataName);
}
Animation *SkeletonData::findAnimation(const String &animationName) {
return ArrayUtils::findWithName(_animations, animationName);
}
Array<Animation *> &SkeletonData::findSliderAnimations(Array<Animation *> &animations) {
for (size_t i = 0, n = _constraints.size(); i < n; i++) {
ConstraintData *constraint = _constraints[i];
if (constraint->getRTTI().instanceOf(SliderData::rtti)) {
SliderData *data = static_cast<SliderData *>(constraint);
if (data->_animation != NULL) animations.add(data->_animation);
}
}
return animations;
}
const String &SkeletonData::getName() {
return _name;
}
void SkeletonData::setName(const String &inValue) {
_name = inValue;
}
Array<BoneData *> &SkeletonData::getBones() {
return _bones;
}
Array<SlotData *> &SkeletonData::getSlots() {
return _slots;
}
Array<Skin *> &SkeletonData::getSkins() {
return _skins;
}
Skin *SkeletonData::getDefaultSkin() {
return _defaultSkin;
}
void SkeletonData::setDefaultSkin(Skin *inValue) {
_defaultSkin = inValue;
}
Array<EventData *> &SkeletonData::getEvents() {
return _events;
}
Array<Animation *> &SkeletonData::getAnimations() {
return _animations;
}
float SkeletonData::getX() {
return _x;
}
void SkeletonData::setX(float inValue) {
_x = inValue;
}
float SkeletonData::getY() {
return _y;
}
void SkeletonData::setY(float inValue) {
_y = inValue;
}
float SkeletonData::getWidth() {
return _width;
}
void SkeletonData::setWidth(float inValue) {
_width = inValue;
}
float SkeletonData::getHeight() {
return _height;
}
void SkeletonData::setHeight(float inValue) {
_height = inValue;
}
float SkeletonData::getReferenceScale() {
return _referenceScale;
}
void SkeletonData::setReferenceScale(float inValue) {
_referenceScale = inValue;
}
const String &SkeletonData::getVersion() {
return _version;
}
void SkeletonData::setVersion(const String &inValue) {
_version = inValue;
}
const String &SkeletonData::getHash() {
return _hash;
}
void SkeletonData::setHash(const String &inValue) {
_hash = inValue;
}
const String &SkeletonData::getImagesPath() {
return _imagesPath;
}
void SkeletonData::setImagesPath(const String &inValue) {
_imagesPath = inValue;
}
const String &SkeletonData::getAudioPath() {
return _audioPath;
}
void SkeletonData::setAudioPath(const String &inValue) {
_audioPath = inValue;
}
float SkeletonData::getFps() {
return _fps;
}
void SkeletonData::setFps(float inValue) {
_fps = inValue;
}
Array<ConstraintData *> &SkeletonData::getConstraints() {
return _constraints;
}

View File

@ -1,248 +0,0 @@
/******************************************************************************
* 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 <spine/SkeletonRenderer.h>
#include <spine/Skeleton.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/RegionAttachment.h>
#include <spine/MeshAttachment.h>
#include <spine/ClippingAttachment.h>
#include <spine/Bone.h>
using namespace spine;
SkeletonRenderer::SkeletonRenderer() : _allocator(4096), _worldVertices(), _quadIndices(), _clipping(), _renderCommands() {
_quadIndices.add(0);
_quadIndices.add(1);
_quadIndices.add(2);
_quadIndices.add(2);
_quadIndices.add(3);
_quadIndices.add(0);
}
SkeletonRenderer::~SkeletonRenderer() {
}
static RenderCommand *createRenderCommand(BlockAllocator &allocator, int numVertices, int32_t numIndices, BlendMode blendMode, void *texture) {
RenderCommand *cmd = allocator.allocate<RenderCommand>(1);
cmd->positions = allocator.allocate<float>(numVertices << 1);
cmd->uvs = allocator.allocate<float>(numVertices << 1);
cmd->colors = allocator.allocate<uint32_t>(numVertices);
cmd->darkColors = allocator.allocate<uint32_t>(numVertices);
cmd->numVertices = numVertices;
cmd->indices = allocator.allocate<uint16_t>(numIndices);
cmd->numIndices = numIndices;
cmd->blendMode = blendMode;
cmd->texture = texture;
cmd->next = nullptr;
return cmd;
}
static RenderCommand *batchSubCommands(BlockAllocator &allocator, Array<RenderCommand *> &commands, int first, int last, int numVertices,
int numIndices) {
RenderCommand *batched = createRenderCommand(allocator, numVertices, numIndices, commands[first]->blendMode, commands[first]->texture);
float *positions = batched->positions;
float *uvs = batched->uvs;
uint32_t *colors = batched->colors;
uint32_t *darkColors = batched->darkColors;
uint16_t *indices = batched->indices;
int indicesOffset = 0;
for (int i = first; i <= last; i++) {
RenderCommand *cmd = commands[i];
memcpy(positions, cmd->positions, sizeof(float) * 2 * cmd->numVertices);
memcpy(uvs, cmd->uvs, sizeof(float) * 2 * cmd->numVertices);
memcpy(colors, cmd->colors, sizeof(int32_t) * cmd->numVertices);
memcpy(darkColors, cmd->darkColors, sizeof(int32_t) * cmd->numVertices);
for (int ii = 0; ii < cmd->numIndices; ii++) indices[ii] = cmd->indices[ii] + indicesOffset;
indicesOffset += cmd->numVertices;
positions += 2 * cmd->numVertices;
uvs += 2 * cmd->numVertices;
colors += cmd->numVertices;
darkColors += cmd->numVertices;
indices += cmd->numIndices;
}
return batched;
}
static RenderCommand *batchCommands(BlockAllocator &allocator, Array<RenderCommand *> &commands) {
if (commands.size() == 0) return nullptr;
RenderCommand *root = nullptr;
RenderCommand *last = nullptr;
RenderCommand *first = commands[0];
int startIndex = 0;
int i = 1;
int numVertices = first->numVertices;
int numIndices = first->numIndices;
while (i <= (int) commands.size()) {
RenderCommand *cmd = i < (int) commands.size() ? commands[i] : nullptr;
if (cmd && cmd->numVertices == 0 && cmd->numIndices == 0) {
i++;
continue;
}
if (cmd != nullptr && cmd->texture == first->texture && cmd->blendMode == first->blendMode && cmd->colors[0] == first->colors[0] &&
cmd->darkColors[0] == first->darkColors[0] && numIndices + cmd->numIndices < 0xffff) {
numVertices += cmd->numVertices;
numIndices += cmd->numIndices;
} else {
RenderCommand *batched = batchSubCommands(allocator, commands, startIndex, i - 1, numVertices, numIndices);
if (!last) {
root = last = batched;
} else {
last->next = batched;
last = batched;
}
if (i == (int) commands.size()) break;
first = commands[i];
startIndex = i;
numVertices = first->numVertices;
numIndices = first->numIndices;
}
i++;
}
return root;
}
RenderCommand *SkeletonRenderer::render(Skeleton &skeleton) {
_allocator.compress();
_renderCommands.clear();
SkeletonClipping &clipper = _clipping;
for (unsigned i = 0; i < skeleton.getSlots().size(); ++i) {
Slot &slot = *skeleton.getDrawOrder()[i];
Attachment *attachment = slot.getAppliedPose().getAttachment();
if (!attachment) {
clipper.clipEnd(slot);
continue;
}
// Early out if the slot color is 0 or the bone is not active
if ((slot.getAppliedPose().getColor().a == 0 || !slot.getBone().isActive()) && !attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
clipper.clipEnd(slot);
continue;
}
Array<float> *worldVertices = &_worldVertices;
Array<unsigned short> *quadIndices = &_quadIndices;
Array<float> *vertices = worldVertices;
int32_t verticesCount;
Array<float> *uvs;
Array<unsigned short> *indices;
int32_t indicesCount;
Color *attachmentColor;
void *texture;
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
RegionAttachment *regionAttachment = (RegionAttachment *) attachment;
attachmentColor = &regionAttachment->getColor();
if (attachmentColor->a == 0) {
clipper.clipEnd(slot);
continue;
}
Sequence &sequence = regionAttachment->getSequence();
int sequenceIndex = sequence.resolveIndex(slot.getAppliedPose());
TextureRegion *region = sequence.getRegion(sequenceIndex);
worldVertices->setSize(8, 0);
regionAttachment->computeWorldVertices(slot, regionAttachment->getOffsets(slot.getAppliedPose()), *worldVertices, 0, 2);
verticesCount = 4;
uvs = &sequence.getUVs(sequenceIndex);
indices = quadIndices;
indicesCount = 6;
texture = region->_rendererObject;
} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
MeshAttachment *mesh = (MeshAttachment *) attachment;
attachmentColor = &mesh->getColor();
if (attachmentColor->a == 0) {
clipper.clipEnd(slot);
continue;
}
Sequence &sequence = mesh->getSequence();
int sequenceIndex = sequence.resolveIndex(slot.getAppliedPose());
TextureRegion *region = sequence.getRegion(sequenceIndex);
worldVertices->setSize(mesh->getWorldVerticesLength(), 0);
mesh->computeWorldVertices(skeleton, slot, 0, mesh->getWorldVerticesLength(), worldVertices->buffer(), 0, 2);
verticesCount = (int32_t) (mesh->getWorldVerticesLength() >> 1);
uvs = &sequence.getUVs(sequenceIndex);
indices = &mesh->getTriangles();
indicesCount = (int32_t) indices->size();
texture = region->_rendererObject;
} else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
ClippingAttachment *clip = (ClippingAttachment *) slot.getAppliedPose().getAttachment();
clipper.clipStart(skeleton, slot, clip);
continue;
} else
continue;
uint8_t r = static_cast<uint8_t>(skeleton.getColor().r * slot.getAppliedPose().getColor().r * attachmentColor->r * 255);
uint8_t g = static_cast<uint8_t>(skeleton.getColor().g * slot.getAppliedPose().getColor().g * attachmentColor->g * 255);
uint8_t b = static_cast<uint8_t>(skeleton.getColor().b * slot.getAppliedPose().getColor().b * attachmentColor->b * 255);
uint8_t a = static_cast<uint8_t>(skeleton.getColor().a * slot.getAppliedPose().getColor().a * attachmentColor->a * 255);
uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
uint32_t darkColor = 0xff000000;
if (slot.getAppliedPose().hasDarkColor()) {
Color &slotDarkColor = slot.getAppliedPose().getDarkColor();
darkColor = 0xff000000 | (static_cast<uint8_t>(slotDarkColor.r * 255) << 16) | (static_cast<uint8_t>(slotDarkColor.g * 255) << 8) |
static_cast<uint8_t>(slotDarkColor.b * 255);
}
if (clipper.isClipping()) {
clipper.clipTriangles(*worldVertices, *indices, *uvs, 2);
vertices = &clipper.getClippedVertices();
verticesCount = (int32_t) (clipper.getClippedVertices().size() >> 1);
uvs = &clipper.getClippedUVs();
indices = &clipper.getClippedTriangles();
indicesCount = (int32_t) (clipper.getClippedTriangles().size());
}
RenderCommand *cmd = createRenderCommand(_allocator, verticesCount, indicesCount, slot.getData().getBlendMode(), texture);
_renderCommands.add(cmd);
memcpy(cmd->positions, vertices->buffer(), (verticesCount << 1) * sizeof(float));
memcpy(cmd->uvs, uvs->buffer(), (verticesCount << 1) * sizeof(float));
for (int ii = 0; ii < verticesCount; ii++) {
cmd->colors[ii] = color;
cmd->darkColors[ii] = darkColor;
}
memcpy(cmd->indices, indices->buffer(), indices->size() * sizeof(uint16_t));
clipper.clipEnd(slot);
}
clipper.clipEnd();
return batchCommands(_allocator, _renderCommands);
}

View File

@ -1,192 +0,0 @@
/******************************************************************************
* 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 <spine/Skin.h>
#include <spine/Attachment.h>
#include <spine/MeshAttachment.h>
#include <spine/Skeleton.h>
#include <spine/ConstraintData.h>
#include <spine/Slot.h>
#include <assert.h>
using namespace spine;
Skin::AttachmentMap::AttachmentMap() {
}
static void disposeAttachment(Attachment *attachment) {
if (!attachment) return;
attachment->dereference();
if (attachment->getRefCount() == 0) delete attachment;
}
void Skin::AttachmentMap::put(size_t slotIndex, const String &placeholderName, Attachment *attachment) {
if (slotIndex >= _buckets.size()) _buckets.setSize(slotIndex + 1, Array<Entry>());
Array<Entry> &bucket = _buckets[slotIndex];
int existing = findInBucket(bucket, placeholderName);
attachment->reference();
if (existing >= 0) {
disposeAttachment(bucket[existing]._attachment);
bucket[existing]._attachment = attachment;
} else {
bucket.add(Entry(slotIndex, placeholderName, attachment));
}
}
Attachment *Skin::AttachmentMap::get(size_t slotIndex, const String &placeholderName) {
if (slotIndex >= _buckets.size()) return NULL;
int existing = findInBucket(_buckets[slotIndex], placeholderName);
return existing >= 0 ? _buckets[slotIndex][existing]._attachment : NULL;
}
void Skin::AttachmentMap::remove(size_t slotIndex, const String &placeholderName) {
if (slotIndex >= _buckets.size()) return;
int existing = findInBucket(_buckets[slotIndex], placeholderName);
if (existing >= 0) {
disposeAttachment(_buckets[slotIndex][existing]._attachment);
_buckets[slotIndex].removeAt(existing);
}
}
int Skin::AttachmentMap::findInBucket(Array<Entry> &bucket, const String &placeholderName) {
for (size_t i = 0; i < bucket.size(); i++)
if (bucket[i]._placeholderName == placeholderName) return (int) i;
return -1;
}
Skin::AttachmentMap::Entries Skin::AttachmentMap::getEntries() {
return Skin::AttachmentMap::Entries(_buckets);
}
Skin::Skin(const String &name) : _name(name), _attachments(), _color(0.99607843f, 0.61960787f, 0.30980393f, 1) {
assert(_name.length() > 0);
}
Skin::~Skin() {
Skin::AttachmentMap::Entries entries = _attachments.getEntries();
while (entries.hasNext()) {
Skin::AttachmentMap::Entry entry = entries.next();
disposeAttachment(entry._attachment);
}
}
void Skin::setAttachment(size_t slotIndex, const String &placeholderName, Attachment *attachment) {
_attachments.put(slotIndex, placeholderName, attachment);
}
Attachment *Skin::getAttachment(size_t slotIndex, const String &placeholderName) {
return _attachments.get(slotIndex, placeholderName);
}
void Skin::removeAttachment(size_t slotIndex, const String &placeholderName) {
_attachments.remove(slotIndex, placeholderName);
}
void Skin::findNamesForSlot(size_t slotIndex, Array<String> &names) {
Skin::AttachmentMap::Entries entries = _attachments.getEntries();
while (entries.hasNext()) {
Skin::AttachmentMap::Entry &entry = entries.next();
if (entry._slotIndex == slotIndex) {
names.add(entry._placeholderName);
}
}
}
void Skin::findAttachmentsForSlot(size_t slotIndex, Array<Attachment *> &attachments) {
Skin::AttachmentMap::Entries entries = _attachments.getEntries();
while (entries.hasNext()) {
Skin::AttachmentMap::Entry &entry = entries.next();
if (entry._slotIndex == slotIndex) attachments.add(entry._attachment);
}
}
const String &Skin::getName() {
return _name;
}
Skin::AttachmentMap::Entries Skin::getAttachments() {
return _attachments.getEntries();
}
void Skin::attachAll(Skeleton &skeleton, Skin &oldSkin) {
Array<Slot *> &slots = skeleton.getSlots();
Skin::AttachmentMap::Entries entries = oldSkin.getAttachments();
while (entries.hasNext()) {
Skin::AttachmentMap::Entry &entry = entries.next();
int slotIndex = (int) entry._slotIndex;
Slot *slot = slots[slotIndex];
if (slot->getPose().getAttachment() == entry._attachment) {
Attachment *attachment = getAttachment(slotIndex, entry._placeholderName);
if (attachment) slot->getPose().setAttachment(attachment);
}
}
}
void Skin::addSkin(Skin &other) {
for (size_t i = 0; i < other.getBones().size(); i++)
if (!_bones.contains(other.getBones()[i])) _bones.add(other.getBones()[i]);
for (size_t i = 0; i < other.getConstraints().size(); i++)
if (!_constraints.contains(other.getConstraints()[i])) _constraints.add(other.getConstraints()[i]);
AttachmentMap::Entries entries = other.getAttachments();
while (entries.hasNext()) {
AttachmentMap::Entry &entry = entries.next();
setAttachment(entry._slotIndex, entry._placeholderName, entry._attachment);
}
}
void Skin::copySkin(Skin &other) {
for (size_t i = 0; i < other.getBones().size(); i++)
if (!_bones.contains(other.getBones()[i])) _bones.add(other.getBones()[i]);
for (size_t i = 0; i < other.getConstraints().size(); i++)
if (!_constraints.contains(other.getConstraints()[i])) _constraints.add(other.getConstraints()[i]);
AttachmentMap::Entries entries = other.getAttachments();
while (entries.hasNext()) {
AttachmentMap::Entry &entry = entries.next();
if (entry._attachment->getRTTI().isExactly(MeshAttachment::rtti))
setAttachment(entry._slotIndex, entry._placeholderName, &static_cast<MeshAttachment *>(entry._attachment)->newLinkedMesh());
else
setAttachment(entry._slotIndex, entry._placeholderName, &entry._attachment->copy());
}
}
Array<ConstraintData *> &Skin::getConstraints() {
return _constraints;
}
Array<BoneData *> &Skin::getBones() {
return _bones;
}

View File

@ -1,136 +0,0 @@
/******************************************************************************
* 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 <spine/Slider.h>
#include <spine/Skeleton.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/BonePose.h>
#include <spine/Animation.h>
#include <spine/Timeline.h>
#include <spine/SlotTimeline.h>
#include <spine/ConstraintTimeline.h>
#include <spine/PhysicsConstraintTimeline.h>
#include <spine/SliderData.h>
#include <spine/SliderPose.h>
#include <spine/Slot.h>
#include <spine/PhysicsConstraint.h>
#include <spine/TransformConstraintData.h>
#include <spine/MathUtil.h>
using namespace spine;
RTTI_IMPL(Slider, Constraint)
float Slider::_offsets[6];
Slider::Slider(SliderData &data, Skeleton &skeleton) : SliderBase(data), _bone(NULL) {
if (data._bone != NULL) {
_bone = skeleton._bones[data._bone->getIndex()];
}
}
Slider &Slider::copy(Skeleton &skeleton) {
Slider *copy = new (__FILE__, __LINE__) Slider(_data, skeleton);
copy->_pose.set(_pose);
return *copy;
}
void Slider::update(Skeleton &skeleton, Physics physics) {
SliderPose &p = *_applied;
if (p._mix == 0) return;
Animation *animation = _data._animation;
if (_bone != NULL) {
if (!_bone->isActive()) return;
if (_data._local) _bone->_applied->validateLocalTransform(skeleton);
p._time = _data._offset +
(_data._property->value(skeleton, *_bone->_applied, _data._local, _offsets) - _data._property->_offset) * _data._scale;
if (_data._loop)
p._time = animation->getDuration() + MathUtil::fmod(p._time, animation->getDuration());
else
p._time = MathUtil::max(0.0f, p._time);
}
Array<Bone *> &bones = skeleton._bones;
const Array<int> &indices = animation->getBones();
for (size_t i = 0, n = indices.size(); i < n; i++) bones[indices[i]]->_applied->modifyLocal(skeleton);
animation->apply(skeleton, p._time, p._time, _data._loop, NULL, p._mix, false, _data._additive, false, true);
}
void Slider::sort(Skeleton &skeleton) {
if (_bone != NULL && !_data._local) skeleton.sortBone(_bone);
skeleton._updateCache.add(this);
Array<Bone *> &bones = skeleton._bones;
const Array<int> &indices = _data._animation->getBones();
for (size_t i = 0, n = indices.size(); i < n; i++) {
Bone *bone = bones[indices[i]];
bone->_sorted = false;
skeleton.sortReset(bone->getChildren());
skeleton.constrained(*bone);
}
Array<Timeline *> &timelines = _data._animation->getTimelines();
Array<Slot *> &slots = skeleton._slots;
Array<Constraint *> &constraints = skeleton._constraints;
Array<PhysicsConstraint *> &physics = skeleton._physics;
size_t physicsCount = physics.size();
for (size_t i = 0, n = timelines.size(); i < n; i++) {
Timeline *t = timelines[i];
if (t->getRTTI().instanceOf(SlotTimeline::rtti)) {
SlotTimeline *timeline = (SlotTimeline *) t;
skeleton.constrained(*slots[timeline->getSlotIndex()]);
} else if (t->getRTTI().instanceOf(PhysicsConstraintTimeline::rtti)) {
PhysicsConstraintTimeline *timeline = (PhysicsConstraintTimeline *) t;
if (timeline->getConstraintIndex() == -1) {
for (size_t ii = 0; ii < physicsCount; ii++) skeleton.constrained(*physics[ii]);
} else
skeleton.constrained((Posed &) *constraints[timeline->getConstraintIndex()]);
} else if (t->getRTTI().instanceOf(ConstraintTimeline::rtti)) {
ConstraintTimeline *timeline = (ConstraintTimeline *) t;
int index = timeline->getConstraintIndex();
if (index != -1) skeleton.constrained((Posed &) *constraints[timeline->getConstraintIndex()]);
}
}
}
bool Slider::isSourceActive() {
return _bone == NULL || _bone->isActive();
}
Bone &Slider::getBone() {
return *_bone;
}
void Slider::setBone(Bone &bone) {
_bone = &bone;
}

View File

@ -1,109 +0,0 @@
/******************************************************************************
* 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 <spine/SliderData.h>
#include <spine/Slider.h>
#include <spine/Skeleton.h>
using namespace spine;
RTTI_IMPL(SliderData, ConstraintData)
SliderData::SliderData(const String &name)
: ConstraintDataGeneric<Slider, SliderPose>(name), _animation(NULL), _additive(false), _loop(false), _bone(NULL), _property(NULL), _offset(0.0f),
_scale(0.0f), _local(false) {
}
Constraint &SliderData::create(Skeleton &skeleton) {
return *(new (__FILE__, __LINE__) Slider(*this, skeleton));
}
Animation &SliderData::getAnimation() {
return *_animation;
}
void SliderData::setAnimation(Animation &animation) {
_animation = &animation;
}
bool SliderData::getAdditive() {
return _additive;
}
void SliderData::setAdditive(bool additive) {
_additive = additive;
}
bool SliderData::getLoop() {
return _loop;
}
void SliderData::setLoop(bool loop) {
_loop = loop;
}
BoneData *SliderData::getBone() {
return _bone;
}
void SliderData::setBone(BoneData *bone) {
_bone = bone;
}
FromProperty *SliderData::getProperty() {
return _property;
}
void SliderData::setProperty(FromProperty *property) {
_property = property;
}
float SliderData::getScale() {
return _scale;
}
void SliderData::setScale(float scale) {
_scale = scale;
}
float SliderData::getOffset() {
return _offset;
}
void SliderData::setOffset(float offset) {
_offset = offset;
}
bool SliderData::getLocal() {
return _local;
}
void SliderData::setLocal(bool local) {
_local = local;
}

View File

@ -1,67 +0,0 @@
/******************************************************************************
* 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 <spine/SliderMixTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Slider.h>
#include <spine/SliderData.h>
#include <spine/SliderPose.h>
#include <spine/Property.h>
using namespace spine;
RTTI_IMPL(SliderMixTimeline, ConstraintTimeline1)
SliderMixTimeline::SliderMixTimeline(size_t frameCount, size_t bezierCount, int sliderIndex)
: ConstraintTimeline1(frameCount, bezierCount, sliderIndex, Property_SliderMix) {
PropertyId ids[] = {((PropertyId) Property_SliderMix << 32) | sliderIndex};
setPropertyIds(ids, 1);
_additive = true;
}
SliderMixTimeline::~SliderMixTimeline() {
}
void SliderMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(out);
Slider *constraint = (Slider *) skeleton._constraints[_constraintIndex];
if (constraint->isActive()) {
SliderPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
SliderData &data = constraint->_data;
pose._mix = getAbsoluteValue(time, alpha, fromSetup, add, pose._mix, data._setup._mix);
}
}

View File

@ -1,59 +0,0 @@
/******************************************************************************
* 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 <spine/SliderPose.h>
using namespace spine;
SliderPose::SliderPose() : _time(0), _mix(0) {
}
SliderPose::~SliderPose() {
}
void SliderPose::set(SliderPose &pose) {
_time = pose._time;
_mix = pose._mix;
}
float SliderPose::getTime() {
return _time;
}
void SliderPose::setTime(float time) {
this->_time = time;
}
float SliderPose::getMix() {
return _mix;
}
void SliderPose::setMix(float mix) {
this->_mix = mix;
}

View File

@ -1,67 +0,0 @@
/******************************************************************************
* 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 <spine/SliderTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Slider.h>
#include <spine/SliderData.h>
#include <spine/SliderPose.h>
#include <spine/Property.h>
using namespace spine;
RTTI_IMPL(SliderTimeline, ConstraintTimeline1)
SliderTimeline::SliderTimeline(size_t frameCount, size_t bezierCount, int sliderIndex)
: ConstraintTimeline1(frameCount, bezierCount, sliderIndex, Property_SliderTime) {
PropertyId ids[] = {((PropertyId) Property_SliderTime << 32) | sliderIndex};
setPropertyIds(ids, 1);
_additive = true;
}
SliderTimeline::~SliderTimeline() {
}
void SliderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(out);
Slider *constraint = (Slider *) skeleton._constraints[_constraintIndex];
if (constraint->isActive()) {
SliderPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
SliderData &data = constraint->_data;
pose._time = getAbsoluteValue(time, alpha, fromSetup, add, pose._time, data._setup._time);
}
}

View File

@ -1,64 +0,0 @@
/******************************************************************************
* 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 <spine/Slot.h>
#include <spine/Bone.h>
#include <spine/Skeleton.h>
#include <spine/SlotData.h>
#include <spine/SlotPose.h>
#include <spine/Color.h>
using namespace spine;
Slot::Slot(SlotData &data, Skeleton &skeleton)
: PosedGeneric<SlotData, SlotPose, SlotPose>(data), _skeleton(skeleton), _bone(*skeleton.getBones()[data._boneData._index]), _attachmentState(0) {
if (data.getSetupPose().hasDarkColor()) {
_pose._hasDarkColor = true;
_constrained._hasDarkColor = true;
}
setupPose();
}
Bone &Slot::getBone() {
return _bone;
}
void Slot::setupPose() {
_pose._color.set(_data._setup._color);
if (_pose._hasDarkColor) _pose._darkColor.set(_data._setup._darkColor);
_pose._sequenceIndex = _data._setup._sequenceIndex;
if (_data._attachmentName.isEmpty())
_pose.setAttachment(NULL);
else {
_pose._attachment = NULL;
_pose.setAttachment(_skeleton.getAttachment(_data._index, _data._attachmentName));
}
}

View File

@ -1,64 +0,0 @@
/******************************************************************************
* 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 <spine/SlotCurveTimeline.h>
#include <spine/Bone.h>
#include <spine/Skeleton.h>
#include <spine/Slot.h>
#include <spine/SlotPose.h>
using namespace spine;
RTTI_IMPL_MULTI(SlotCurveTimeline, CurveTimeline, SlotTimeline)
SlotCurveTimeline::SlotCurveTimeline(size_t frameCount, size_t frameEntries, size_t bezierCount, int slotIndex)
: CurveTimeline(frameCount, frameEntries, bezierCount), SlotTimeline(), _slotIndex(slotIndex) {
}
SlotCurveTimeline::~SlotCurveTimeline() {
}
int SlotCurveTimeline::getSlotIndex() {
return _slotIndex;
}
void SlotCurveTimeline::setSlotIndex(int inValue) {
_slotIndex = inValue;
}
void SlotCurveTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add, bool out,
bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(out);
Slot *slot = skeleton._slots[_slotIndex];
if (slot->_bone.isActive()) _apply(*slot, appliedPose ? *slot->_applied : slot->_pose, time, alpha, fromSetup, add);
}

View File

@ -1,73 +0,0 @@
/******************************************************************************
* 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 <spine/SlotData.h>
#include <spine/SlotPose.h>
#include <spine/BoneData.h>
#include <assert.h>
using namespace spine;
SlotData::SlotData(int index, const String &name, BoneData &boneData)
: PosedDataGeneric<SlotPose>(name), _index(index), _boneData(boneData), _attachmentName(), _blendMode(BlendMode_Normal), _visible(true) {
assert(index >= 0);
}
int SlotData::getIndex() {
return _index;
}
BoneData &SlotData::getBoneData() {
return _boneData;
}
void SlotData::setAttachmentName(const String &attachmentName) {
_attachmentName = attachmentName;
}
const String &SlotData::getAttachmentName() {
return _attachmentName;
}
BlendMode SlotData::getBlendMode() {
return _blendMode;
}
void SlotData::setBlendMode(BlendMode blendMode) {
_blendMode = blendMode;
}
bool SlotData::getVisible() {
return _visible;
}
void SlotData::setVisible(bool visible) {
_visible = visible;
}

View File

@ -1,91 +0,0 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, 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 <spine/SlotPose.h>
#include <spine/Attachment.h>
#include <spine/VertexAttachment.h>
using namespace spine;
SlotPose::SlotPose() : _color(1, 1, 1, 1), _darkColor(0, 0, 0, 0), _hasDarkColor(false), _attachment(nullptr), _sequenceIndex(0) {
}
SlotPose::~SlotPose() {
}
void SlotPose::set(SlotPose &pose) {
_color.set(pose._color);
if (pose._hasDarkColor) _darkColor.set(pose._darkColor);
_hasDarkColor = pose._hasDarkColor;
_attachment = pose._attachment;
_sequenceIndex = pose._sequenceIndex;
_deform.clear();
_deform.addAll(pose._deform);
}
Color &SlotPose::getColor() {
return _color;
}
Color &SlotPose::getDarkColor() {
return _darkColor;
}
bool SlotPose::hasDarkColor() {
return _hasDarkColor;
}
void SlotPose::setHasDarkColor(bool hasDarkColor) {
_hasDarkColor = hasDarkColor;
}
Attachment *SlotPose::getAttachment() {
return _attachment;
}
void SlotPose::setAttachment(Attachment *attachment) {
if (_attachment == attachment) return;
// Check if we need to clear deform based on timeline attachment.
if (!attachment || !_attachment || attachment->getTimelineAttachment() != _attachment->getTimelineAttachment()) _deform.clear();
_attachment = attachment;
_sequenceIndex = -1;
}
int SlotPose::getSequenceIndex() {
return _sequenceIndex;
}
void SlotPose::setSequenceIndex(int sequenceIndex) {
_sequenceIndex = sequenceIndex;
}
Array<float> &SlotPose::getDeform() {
return _deform;
}

View File

@ -1,40 +0,0 @@
/******************************************************************************
* 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 <spine/SlotTimeline.h>
using namespace spine;
RTTI_IMPL_NOPARENT(SlotTimeline)
SlotTimeline::SlotTimeline() {
}
SlotTimeline::~SlotTimeline() {
}

View File

@ -1,63 +0,0 @@
/******************************************************************************
* 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 <spine/SpineObject.h>
#include <spine/Extension.h>
using namespace spine;
void *SpineObject::operator new(size_t sz) {
return SpineExtension::getInstance()->_calloc(sz, __FILE__, __LINE__);
}
void *SpineObject::operator new(size_t sz, const char *file, int line) {
return SpineExtension::getInstance()->_calloc(sz, file, line);
}
void *SpineObject::operator new(size_t sz, void *ptr) {
SP_UNUSED(sz);
return ptr;
}
void SpineObject::operator delete(void *p, const char *file, int line) {
SpineExtension::free(p, file, line);
}
void SpineObject::operator delete(void *p, void *mem) {
SP_UNUSED(mem);
SpineExtension::free(p, __FILE__, __LINE__);
}
void SpineObject::operator delete(void *p) {
SpineExtension::free(p, __FILE__, __LINE__);
}
SpineObject::~SpineObject() {
SpineExtension::beforeFree(this);
}

View File

@ -1,38 +0,0 @@
/******************************************************************************
* 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 <spine/TextureLoader.h>
namespace spine {
TextureLoader::TextureLoader() {
}
TextureLoader::~TextureLoader() {
}
}// namespace spine

View File

@ -1,34 +0,0 @@
/******************************************************************************
* 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 <spine/TextureRegion.h>
using namespace spine;
RTTI_IMPL_NOPARENT(TextureRegion)

View File

@ -1,73 +0,0 @@
/******************************************************************************
* 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 <spine/Timeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
using namespace spine;
RTTI_IMPL_NOPARENT(Timeline)
Timeline::Timeline(size_t frameCount, size_t frameEntries)
: _propertyIds(), _frames(), _frameEntries(frameEntries), _additive(false), _instant(false) {
_frames.setSize(frameCount * frameEntries, 0);
}
Timeline::~Timeline() {
}
Array<PropertyId> &Timeline::getPropertyIds() {
return _propertyIds;
}
void Timeline::setPropertyIds(PropertyId propertyIds[], size_t propertyIdsCount) {
_propertyIds.clear();
_propertyIds.ensureCapacity(propertyIdsCount);
for (size_t i = 0; i < propertyIdsCount; i++) {
_propertyIds.add(propertyIds[i]);
}
}
size_t Timeline::getFrameCount() {
return _frames.size() / _frameEntries;
}
Array<float> &Timeline::getFrames() {
return _frames;
}
size_t Timeline::getFrameEntries() {
return _frameEntries;
}
float Timeline::getDuration() {
return _frames[_frames.size() - getFrameEntries()];
}

View File

@ -1,139 +0,0 @@
/******************************************************************************
* 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 <spine/TransformConstraint.h>
#include <spine/Bone.h>
#include <spine/BonePose.h>
#include <spine/Skeleton.h>
#include <spine/TransformConstraintData.h>
#include <spine/MathUtil.h>
#include <spine/BoneData.h>
using namespace spine;
RTTI_IMPL(TransformConstraint, Constraint)
TransformConstraint::TransformConstraint(TransformConstraintData &data, Skeleton &skeleton) : TransformConstraintBase(data) {
_bones.ensureCapacity(data.getBones().size());
for (size_t i = 0; i < data.getBones().size(); i++) {
BoneData *boneData = data.getBones()[i];
_bones.add(&skeleton._bones[boneData->getIndex()]->_constrained);
}
_source = skeleton._bones[data._source->getIndex()];
}
TransformConstraint &TransformConstraint::copy(Skeleton &skeleton) {
TransformConstraint *copy = new (__FILE__, __LINE__) TransformConstraint(_data, skeleton);
copy->_pose.set(_pose);
return *copy;
}
/// Applies the constraint to the constrained bones.
void TransformConstraint::update(Skeleton &skeleton, Physics physics) {
TransformConstraintPose &p = *_applied;
if (p._mixRotate == 0 && p._mixX == 0 && p._mixY == 0 && p._mixScaleX == 0 && p._mixScaleY == 0 && p._mixShearY == 0) return;
TransformConstraintData &data = _data;
bool localSource = data._localSource, localTarget = data._localTarget, additive = data._additive, clamp = data._clamp;
float *offsets = data._offsets;
BonePose &source = *_source->_applied;
if (localSource) {
source.validateLocalTransform(skeleton);
}
FromProperty **fromItems = data._properties.buffer();
size_t fn = data._properties.size();
int update = skeleton._update;
BonePose **bones = _bones.buffer();
for (size_t i = 0, n = _bones.size(); i < n; i++) {
BonePose *bone = bones[i];
if (localTarget) {
bone->modifyLocal(skeleton);
} else {
bone->modifyWorld(update);
}
for (size_t f = 0; f < fn; f++) {
FromProperty *from = fromItems[f];
float value = from->value(skeleton, source, localSource, offsets) - from->_offset;
Array<ToProperty *> &toProps = from->_to;
ToProperty **toItems = toProps.buffer();
for (size_t t = 0, tn = toProps.size(); t < tn; t++) {
ToProperty *to = toItems[t];
if (to->mix(p) != 0) {
float clamped = to->_offset + value * to->_scale;
if (clamp) {
if (to->_offset < to->_max)
clamped = MathUtil::clamp(clamped, to->_offset, to->_max);
else
clamped = MathUtil::clamp(clamped, to->_max, to->_offset);
}
to->apply(skeleton, p, *bone, clamped, localTarget, additive);
}
}
}
}
}
void TransformConstraint::sort(Skeleton &skeleton) {
if (!_data._localSource) skeleton.sortBone(_source);
BonePose **bones = _bones.buffer();
size_t boneCount = _bones.size();
bool worldTarget = !_data._localTarget;
if (worldTarget) {
for (size_t i = 0; i < boneCount; i++) skeleton.sortBone(bones[i]->_bone);
}
skeleton._updateCache.add(this);
for (size_t i = 0; i < boneCount; i++) {
Bone *bone = bones[i]->_bone;
skeleton.sortReset(bone->_children);
skeleton.constrained(*bone);
}
for (size_t i = 0; i < boneCount; i++) bones[i]->_bone->_sorted = worldTarget;
}
bool TransformConstraint::isSourceActive() {
return _source->_active;
}
/// The bones that will be modified by this transform constraint.
Array<BonePose *> &TransformConstraint::getBones() {
return _bones;
}
/// The bone whose world transform will be copied to the constrained bones.
Bone &TransformConstraint::getSource() {
return *_source;
}
void TransformConstraint::setSource(Bone &source) {
_source = &source;
}

View File

@ -1,363 +0,0 @@
/******************************************************************************
* 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 <spine/TransformConstraintData.h>
#include <spine/TransformConstraint.h>
#include <spine/BoneData.h>
#include <spine/BonePose.h>
#include <spine/TransformConstraintPose.h>
#include <spine/MathUtil.h>
#include <spine/ArrayUtils.h>
#include <spine/Skeleton.h>
using namespace spine;
// Define static constants for TransformConstraintData
const int TransformConstraintData::ROTATION = 0;
const int TransformConstraintData::X = 1;
const int TransformConstraintData::Y = 2;
const int TransformConstraintData::SCALEX = 3;
const int TransformConstraintData::SCALEY = 4;
const int TransformConstraintData::SHEARY = 5;
RTTI_IMPL(TransformConstraintData, ConstraintData)
RTTI_IMPL_NOPARENT(FromProperty)
RTTI_IMPL_NOPARENT(ToProperty)
RTTI_IMPL(FromRotate, FromProperty)
RTTI_IMPL(ToRotate, ToProperty)
RTTI_IMPL(FromX, FromProperty)
RTTI_IMPL(ToX, ToProperty)
RTTI_IMPL(FromY, FromProperty)
RTTI_IMPL(ToY, ToProperty)
RTTI_IMPL(FromScaleX, FromProperty)
RTTI_IMPL(ToScaleX, ToProperty)
RTTI_IMPL(FromScaleY, FromProperty)
RTTI_IMPL(ToScaleY, ToProperty)
RTTI_IMPL(FromShearY, FromProperty)
RTTI_IMPL(ToShearY, ToProperty)
TransformConstraintData::TransformConstraintData(const String &name)
: ConstraintDataGeneric<TransformConstraint, TransformConstraintPose>(name), _source(NULL), _localSource(false), _localTarget(false),
_additive(false), _clamp(false) {
for (int i = 0; i < 6; i++) {
_offsets[i] = 0;
}
}
Array<BoneData *> &TransformConstraintData::getBones() {
return _bones;
}
BoneData &TransformConstraintData::getSource() {
return *_source;
}
void TransformConstraintData::setSource(BoneData &source) {
_source = &source;
}
float TransformConstraintData::getOffsetRotation() {
return _offsets[ROTATION];
}
void TransformConstraintData::setOffsetRotation(float offsetRotation) {
_offsets[ROTATION] = offsetRotation;
}
float TransformConstraintData::getOffsetX() {
return _offsets[X];
}
void TransformConstraintData::setOffsetX(float offsetX) {
_offsets[X] = offsetX;
}
float TransformConstraintData::getOffsetY() {
return _offsets[Y];
}
void TransformConstraintData::setOffsetY(float offsetY) {
_offsets[Y] = offsetY;
}
float TransformConstraintData::getOffsetScaleX() {
return _offsets[SCALEX];
}
void TransformConstraintData::setOffsetScaleX(float offsetScaleX) {
_offsets[SCALEX] = offsetScaleX;
}
float TransformConstraintData::getOffsetScaleY() {
return _offsets[SCALEY];
}
void TransformConstraintData::setOffsetScaleY(float offsetScaleY) {
_offsets[SCALEY] = offsetScaleY;
}
float TransformConstraintData::getOffsetShearY() {
return _offsets[SHEARY];
}
void TransformConstraintData::setOffsetShearY(float offsetShearY) {
_offsets[SHEARY] = offsetShearY;
}
bool TransformConstraintData::getLocalSource() {
return _localSource;
}
void TransformConstraintData::setLocalSource(bool localSource) {
_localSource = localSource;
}
bool TransformConstraintData::getLocalTarget() {
return _localTarget;
}
void TransformConstraintData::setLocalTarget(bool localTarget) {
_localTarget = localTarget;
}
bool TransformConstraintData::getAdditive() {
return _additive;
}
void TransformConstraintData::setAdditive(bool additive) {
_additive = additive;
}
bool TransformConstraintData::getClamp() {
return _clamp;
}
void TransformConstraintData::setClamp(bool clamp) {
_clamp = clamp;
}
Array<FromProperty *> &TransformConstraintData::getProperties() {
return _properties;
}
FromProperty::FromProperty() : SpineObject(), _offset(0) {
}
FromProperty::~FromProperty() {
}
ToProperty::ToProperty() : SpineObject(), _offset(0), _max(0), _scale(1) {
}
ToProperty::~ToProperty() {
}
float FromRotate::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._rotation + offsets[TransformConstraintData::ROTATION];
float sx = skeleton.getScaleX(), sy = skeleton.getScaleY();
float value = MathUtil::atan2(source._c / sy, source._a / sx) * MathUtil::Rad_Deg +
((source._a * source._d - source._b * source._c) * sx * sy > 0 ? offsets[TransformConstraintData::ROTATION]
: -offsets[TransformConstraintData::ROTATION]);
if (value < 0) value += 360;
return value;
}
float ToRotate::mix(TransformConstraintPose &pose) {
return pose._mixRotate;
}
void ToRotate::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) {
bone._rotation += (additive ? value : value - bone._rotation) * pose._mixRotate;
} else {
float sx = skeleton.getScaleX(), sy = skeleton.getScaleY(), ix = 1 / sx, iy = 1 / sy;
float a = bone._a * ix, b = bone._b * ix, c = bone._c * iy, d = bone._d * iy;
value *= MathUtil::Deg_Rad;
if (!additive) value -= MathUtil::atan2(c, a);
if (value > MathUtil::Pi)
value -= MathUtil::Pi_2;
else if (value < -MathUtil::Pi)//
value += MathUtil::Pi_2;
value *= pose._mixRotate;
float cosVal = MathUtil::cos(value), sinVal = MathUtil::sin(value);
bone._a = (cosVal * a - sinVal * c) * sx;
bone._b = (cosVal * b - sinVal * d) * sx;
bone._c = (sinVal * a + cosVal * c) * sy;
bone._d = (sinVal * b + cosVal * d) * sy;
}
}
float FromX::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
return local
? source._x + offsets[TransformConstraintData::X]
: (offsets[TransformConstraintData::X] * source._a + offsets[TransformConstraintData::Y] * source._b + source._worldX) / skeleton.getScaleX();
}
float ToX::mix(TransformConstraintPose &pose) {
return pose._mixX;
}
void ToX::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) {
bone._x += (additive ? value : value - bone._x) * pose._mixX;
} else {
if (!additive) value -= bone._worldX / skeleton.getScaleX();
bone._worldX += value * pose._mixX * skeleton.getScaleX();
}
}
float FromY::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
return local
? source._y + offsets[TransformConstraintData::Y]
: (offsets[TransformConstraintData::X] * source._c + offsets[TransformConstraintData::Y] * source._d + source._worldY) / skeleton.getScaleY();
}
float ToY::mix(TransformConstraintPose &pose) {
return pose._mixY;
}
void ToY::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) {
bone._y += (additive ? value : value - bone._y) * pose._mixY;
} else {
if (!additive) value -= bone._worldY / skeleton.getScaleY();
bone._worldY += value * pose._mixY * skeleton.getScaleY();
}
}
float FromScaleX::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._scaleX + offsets[TransformConstraintData::SCALEX];
float a = source._a / skeleton.getScaleX(), c = source._c / skeleton.getScaleY();
return MathUtil::sqrt(a * a + c * c) + offsets[TransformConstraintData::SCALEX];
}
float ToScaleX::mix(TransformConstraintPose &pose) {
return pose._mixScaleX;
}
void ToScaleX::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) {
if (additive)
bone._scaleX *= 1 + (value - 1) * pose._mixScaleX;
else if (bone._scaleX != 0)//
bone._scaleX += (value - bone._scaleX) * pose._mixScaleX;
} else if (additive) {
float s = 1 + (value - 1) * pose._mixScaleX;
bone._a *= s;
bone._c *= s;
} else {
float a = bone._a / skeleton.getScaleX(), c = bone._c / skeleton.getScaleY(), s = MathUtil::sqrt(a * a + c * c);
if (s != 0) {
s = 1 + (value - s) * pose._mixScaleX / s;
bone._a *= s;
bone._c *= s;
}
}
}
float FromScaleY::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._scaleY + offsets[TransformConstraintData::SCALEY];
float b = source._b / skeleton.getScaleX(), d = source._d / skeleton.getScaleY();
return MathUtil::sqrt(b * b + d * d) + offsets[TransformConstraintData::SCALEY];
}
float ToScaleY::mix(TransformConstraintPose &pose) {
return pose._mixScaleY;
}
void ToScaleY::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) {
if (additive)
bone._scaleY *= 1 + (value - 1) * pose._mixScaleY;
else if (bone._scaleY != 0)//
bone._scaleY += (value - bone._scaleY) * pose._mixScaleY;
} else if (additive) {
float s = 1 + (value - 1) * pose._mixScaleY;
bone._b *= s;
bone._d *= s;
} else {
float b = bone._b / skeleton.getScaleX(), d = bone._d / skeleton.getScaleY(), s = MathUtil::sqrt(b * b + d * d);
if (s != 0) {
s = 1 + (value - s) * pose._mixScaleY / s;
bone._b *= s;
bone._d *= s;
}
}
}
float FromShearY::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._shearY + offsets[TransformConstraintData::SHEARY];
float ix = 1 / skeleton.getScaleX(), iy = 1 / skeleton.getScaleY();
return (MathUtil::atan2(source._d * iy, source._b * ix) - MathUtil::atan2(source._c * iy, source._a * ix)) * MathUtil::Rad_Deg - 90 +
offsets[TransformConstraintData::SHEARY];
}
float ToShearY::mix(TransformConstraintPose &pose) {
return pose._mixShearY;
}
void ToShearY::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) {
if (!additive) value -= bone._shearY;
bone._shearY += value * pose._mixShearY;
} else {
float sx = skeleton.getScaleX(), sy = skeleton.getScaleY(), b = bone._b / sx, d = bone._d / sy, by = MathUtil::atan2(d, b);
value = (value + 90) * MathUtil::Deg_Rad;
if (additive)
value -= MathUtil::Pi / 2;
else {
value -= by - MathUtil::atan2(bone._c / sy, bone._a / sx);
if (value > MathUtil::Pi)
value -= MathUtil::Pi_2;
else if (value < -MathUtil::Pi)//
value += MathUtil::Pi_2;
}
value = by + value * pose._mixShearY;
float s = MathUtil::sqrt(b * b + d * d);
bone._b = MathUtil::cos(value) * s * sx;
bone._d = MathUtil::sin(value) * s * sy;
}
}
TransformConstraintData::~TransformConstraintData() {
// Clean up all FromProperty objects, which will in turn clean up their ToProperty objects
for (size_t i = 0; i < _properties.size(); i++) {
FromProperty *fromProp = _properties[i];
if (fromProp) {
// Clean up the ToProperty objects in the FromProperty
ArrayUtils::deleteElements(fromProp->_to);
delete fromProp;
}
}
_properties.clear();
}
Constraint &TransformConstraintData::create(Skeleton &skeleton) {
return *(new (__FILE__, __LINE__) TransformConstraint(*this, skeleton));
}

View File

@ -1,95 +0,0 @@
/******************************************************************************
* 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 <spine/TransformConstraintPose.h>
using namespace spine;
TransformConstraintPose::TransformConstraintPose() : _mixRotate(0), _mixX(0), _mixY(0), _mixScaleX(0), _mixScaleY(0), _mixShearY(0) {
}
TransformConstraintPose::~TransformConstraintPose() {
}
void TransformConstraintPose::set(TransformConstraintPose &pose) {
_mixRotate = pose._mixRotate;
_mixX = pose._mixX;
_mixY = pose._mixY;
_mixScaleX = pose._mixScaleX;
_mixScaleY = pose._mixScaleY;
_mixShearY = pose._mixShearY;
}
float TransformConstraintPose::getMixRotate() {
return _mixRotate;
}
void TransformConstraintPose::setMixRotate(float mixRotate) {
this->_mixRotate = mixRotate;
}
float TransformConstraintPose::getMixX() {
return _mixX;
}
void TransformConstraintPose::setMixX(float mixX) {
this->_mixX = mixX;
}
float TransformConstraintPose::getMixY() {
return _mixY;
}
void TransformConstraintPose::setMixY(float mixY) {
this->_mixY = mixY;
}
float TransformConstraintPose::getMixScaleX() {
return _mixScaleX;
}
void TransformConstraintPose::setMixScaleX(float mixScaleX) {
this->_mixScaleX = mixScaleX;
}
float TransformConstraintPose::getMixScaleY() {
return _mixScaleY;
}
void TransformConstraintPose::setMixScaleY(float mixScaleY) {
this->_mixScaleY = mixScaleY;
}
float TransformConstraintPose::getMixShearY() {
return _mixShearY;
}
void TransformConstraintPose::setMixShearY(float mixShearY) {
this->_mixShearY = mixShearY;
}

View File

@ -1,148 +0,0 @@
/******************************************************************************
* 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 <spine/TransformConstraintTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Property.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/TransformConstraint.h>
#include <spine/TransformConstraintData.h>
#include <spine/TransformConstraintPose.h>
using namespace spine;
RTTI_IMPL_MULTI(TransformConstraintTimeline, CurveTimeline, ConstraintTimeline)
TransformConstraintTimeline::TransformConstraintTimeline(size_t frameCount, size_t bezierCount, int transformConstraintIndex)
: CurveTimeline(frameCount, TransformConstraintTimeline::ENTRIES, bezierCount), ConstraintTimeline(), _constraintIndex(transformConstraintIndex) {
PropertyId ids[] = {((PropertyId) Property_TransformConstraint << 32) | transformConstraintIndex};
setPropertyIds(ids, 1);
_additive = true;
}
TransformConstraintTimeline::~TransformConstraintTimeline() {
}
void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Array<Event *> *events, float alpha, bool fromSetup, bool add,
bool out, bool appliedPose) {
SP_UNUSED(lastTime);
SP_UNUSED(events);
SP_UNUSED(out);
TransformConstraint *constraint = (TransformConstraint *) skeleton._constraints[_constraintIndex];
if (!constraint->isActive()) return;
TransformConstraintPose &pose = appliedPose ? *constraint->_applied : constraint->_pose;
if (time < _frames[0]) {
if (fromSetup) {
TransformConstraintPose &setup = constraint->_data._setup;
pose._mixRotate = setup._mixRotate;
pose._mixX = setup._mixX;
pose._mixY = setup._mixY;
pose._mixScaleX = setup._mixScaleX;
pose._mixScaleY = setup._mixScaleY;
pose._mixShearY = setup._mixShearY;
}
return;
}
float rotate, x, y, scaleX, scaleY, shearY;
int i = Animation::search(_frames, time, ENTRIES);
int curveType = (int) _curves[i / ENTRIES];
switch (curveType) {
case LINEAR: {
float before = _frames[i];
rotate = _frames[i + ROTATE];
x = _frames[i + X];
y = _frames[i + Y];
scaleX = _frames[i + SCALEX];
scaleY = _frames[i + SCALEY];
shearY = _frames[i + SHEARY];
float t = (time - before) / (_frames[i + ENTRIES] - before);
rotate += (_frames[i + ENTRIES + ROTATE] - rotate) * t;
x += (_frames[i + ENTRIES + X] - x) * t;
y += (_frames[i + ENTRIES + Y] - y) * t;
scaleX += (_frames[i + ENTRIES + SCALEX] - scaleX) * t;
scaleY += (_frames[i + ENTRIES + SCALEY] - scaleY) * t;
shearY += (_frames[i + ENTRIES + SHEARY] - shearY) * t;
break;
}
case STEPPED: {
rotate = _frames[i + ROTATE];
x = _frames[i + X];
y = _frames[i + Y];
scaleX = _frames[i + SCALEX];
scaleY = _frames[i + SCALEY];
shearY = _frames[i + SHEARY];
break;
}
default: {
rotate = getBezierValue(time, i, ROTATE, curveType - BEZIER);
x = getBezierValue(time, i, X, curveType + BEZIER_SIZE - BEZIER);
y = getBezierValue(time, i, Y, curveType + BEZIER_SIZE * 2 - BEZIER);
scaleX = getBezierValue(time, i, SCALEX, curveType + BEZIER_SIZE * 3 - BEZIER);
scaleY = getBezierValue(time, i, SCALEY, curveType + BEZIER_SIZE * 4 - BEZIER);
shearY = getBezierValue(time, i, SHEARY, curveType + BEZIER_SIZE * 5 - BEZIER);
}
}
TransformConstraintPose &base = fromSetup ? constraint->_data._setup : pose;
if (add) {
pose._mixRotate = base._mixRotate + rotate * alpha;
pose._mixX = base._mixX + x * alpha;
pose._mixY = base._mixY + y * alpha;
pose._mixScaleX = base._mixScaleX + scaleX * alpha;
pose._mixScaleY = base._mixScaleY + scaleY * alpha;
pose._mixShearY = base._mixShearY + shearY * alpha;
} else {
pose._mixRotate = base._mixRotate + (rotate - base._mixRotate) * alpha;
pose._mixX = base._mixX + (x - base._mixX) * alpha;
pose._mixY = base._mixY + (y - base._mixY) * alpha;
pose._mixScaleX = base._mixScaleX + (scaleX - base._mixScaleX) * alpha;
pose._mixScaleY = base._mixScaleY + (scaleY - base._mixScaleY) * alpha;
pose._mixShearY = base._mixShearY + (shearY - base._mixShearY) * alpha;
}
}
void TransformConstraintTimeline::setFrame(int frame, float time, float mixRotate, float mixX, float mixY, float mixScaleX, float mixScaleY,
float mixShearY) {
frame *= ENTRIES;
_frames[frame] = time;
_frames[frame + ROTATE] = mixRotate;
_frames[frame + X] = mixX;
_frames[frame + Y] = mixY;
_frames[frame + SCALEX] = mixScaleX;
_frames[frame + SCALEY] = mixScaleY;
_frames[frame + SHEARY] = mixShearY;
}

View File

@ -1,115 +0,0 @@
/******************************************************************************
* 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 <spine/TranslateTimeline.h>
#include <spine/Event.h>
#include <spine/Skeleton.h>
#include <spine/Animation.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
using namespace spine;
RTTI_IMPL(TranslateTimeline, BoneTimeline2)
TranslateTimeline::TranslateTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline2(frameCount, bezierCount, boneIndex, Property_X, Property_Y) {
}
void TranslateTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
SP_UNUSED(out);
if (time < _frames[0]) {
if (fromSetup) {
pose._x = setup._x;
pose._y = setup._y;
}
return;
}
float x, y;
int i = Animation::search(_frames, time, BoneTimeline2::ENTRIES);
int curveType = (int) _curves[i / BoneTimeline2::ENTRIES];
switch (curveType) {
case CurveTimeline::LINEAR: {
float before = _frames[i];
x = _frames[i + BoneTimeline2::VALUE1];
y = _frames[i + BoneTimeline2::VALUE2];
float t = (time - before) / (_frames[i + BoneTimeline2::ENTRIES] - before);
x += (_frames[i + BoneTimeline2::ENTRIES + BoneTimeline2::VALUE1] - x) * t;
y += (_frames[i + BoneTimeline2::ENTRIES + BoneTimeline2::VALUE2] - y) * t;
break;
}
case CurveTimeline::STEPPED: {
x = _frames[i + BoneTimeline2::VALUE1];
y = _frames[i + BoneTimeline2::VALUE2];
break;
}
default: {
x = getBezierValue(time, i, BoneTimeline2::VALUE1, curveType - BoneTimeline2::BEZIER);
y = getBezierValue(time, i, BoneTimeline2::VALUE2, curveType + BoneTimeline2::BEZIER_SIZE - BoneTimeline2::BEZIER);
}
}
if (fromSetup) {
pose._x = setup._x + x * alpha;
pose._y = setup._y + y * alpha;
} else if (add) {
pose._x += x * alpha;
pose._y += y * alpha;
} else {
pose._x += (setup._x + x - pose._x) * alpha;
pose._y += (setup._y + y - pose._y) * alpha;
}
}
RTTI_IMPL(TranslateXTimeline, BoneTimeline1)
TranslateXTimeline::TranslateXTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline1(frameCount, bezierCount, boneIndex, Property_X) {
}
void TranslateXTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
SP_UNUSED(out);
pose._x = getRelativeValue(time, alpha, fromSetup, add, pose._x, setup._x);
}
RTTI_IMPL(TranslateYTimeline, BoneTimeline1)
TranslateYTimeline::TranslateYTimeline(size_t frameCount, size_t bezierCount, int boneIndex)
: BoneTimeline1(frameCount, bezierCount, boneIndex, Property_Y) {
}
void TranslateYTimeline::_apply(BoneLocal &pose, BoneLocal &setup, float time, float alpha, bool fromSetup, bool add, bool out) {
SP_UNUSED(out);
pose._y = getRelativeValue(time, alpha, fromSetup, add, pose._y, setup._y);
}

View File

@ -1,281 +0,0 @@
/******************************************************************************
* 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 <spine/Triangulator.h>
#include <spine/MathUtil.h>
using namespace spine;
Triangulator::~Triangulator() {
ArrayUtils::deleteElements(_convexPolygons);
ArrayUtils::deleteElements(_convexPolygonsIndices);
}
Array<int> &Triangulator::triangulate(Array<float> &vertices) {
size_t vertexCount = vertices.size() >> 1;
Array<int> &indices = _indices;
indices.clear();
indices.ensureCapacity(vertexCount);
indices.setSize(vertexCount, 0);
for (int i = 0; i < (int) vertexCount; ++i) {
indices[i] = i;
}
Array<bool> &isConcaveArray = _isConcaveArray;
isConcaveArray.ensureCapacity(vertexCount);
isConcaveArray.setSize(vertexCount, 0);
for (int i = 0, n = (int) vertexCount; i < n; ++i) {
isConcaveArray[i] = isConcave(i, (int) vertexCount, vertices, indices);
}
Array<int> &triangles = _triangles;
triangles.clear();
triangles.ensureCapacity(MathUtil::max((int) 0, (int) vertexCount - 2) << 2);
while (vertexCount > 3) {
// Find ear tip.
size_t previous = vertexCount - 1, i = 0, next = 1;
// outer:
while (true) {
if (!isConcaveArray[i]) {
int p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1;
float p1x = vertices[p1], p1y = vertices[p1 + 1];
float p2x = vertices[p2], p2y = vertices[p2 + 1];
float p3x = vertices[p3], p3y = vertices[p3 + 1];
for (size_t ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) {
if (!isConcaveArray[ii]) continue;
int v = indices[ii] << 1;
float &vx = vertices[v], vy = vertices[v + 1];
if (positiveArea(p3x, p3y, p1x, p1y, vx, vy)) {
if (positiveArea(p1x, p1y, p2x, p2y, vx, vy)) {
if (positiveArea(p2x, p2y, p3x, p3y, vx, vy)) {
goto break_outer;// break outer;
}
}
}
}
break;
}
break_outer:
if (next == 0) {
do {
if (!isConcaveArray[i]) break;
i--;
} while (i > 0);
break;
}
previous = i;
i = next;
next = (next + 1) % vertexCount;
}
// Cut ear tip.
triangles.add(indices[(vertexCount + i - 1) % vertexCount]);
triangles.add(indices[i]);
triangles.add(indices[(i + 1) % vertexCount]);
indices.removeAt(i);
isConcaveArray.removeAt(i);
vertexCount--;
int previousIndex = (int) ((vertexCount + i - 1) % vertexCount);
int nextIndex = (int) (i == vertexCount ? 0 : i);
isConcaveArray[previousIndex] = isConcave(previousIndex, (int) vertexCount, vertices, indices);
isConcaveArray[nextIndex] = isConcave(nextIndex, (int) vertexCount, vertices, indices);
}
if (vertexCount == 3) {
triangles.add(indices[2]);
triangles.add(indices[0]);
triangles.add(indices[1]);
}
return triangles;
}
Array<Array<float> *> &Triangulator::decompose(Array<float> &vertices, Array<int> &triangles) {
Array<Array<float> *> &convexPolygons = _convexPolygons;
for (size_t i = 0, n = convexPolygons.size(); i < n; ++i) _polygonPool.free(convexPolygons[i]);
convexPolygons.clear();
Array<Array<int> *> &convexPolygonsIndices = _convexPolygonsIndices;
for (size_t i = 0, n = convexPolygonsIndices.size(); i < n; ++i) _polygonIndicesPool.free(convexPolygonsIndices[i]);
convexPolygonsIndices.clear();
Array<int> *polygonIndices = _polygonIndicesPool.obtain();
polygonIndices->clear();
Array<float> *polygon = _polygonPool.obtain();
polygon->clear();
// Merge subsequent triangles if they form a triangle fan.
int fanBaseIndex = -1, lastwinding = 0;
for (size_t i = 0, n = triangles.size(); i < n; i += 3) {
int t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1;
float x1 = vertices[t1], y1 = vertices[t1 + 1];
float x2 = vertices[t2], y2 = vertices[t2 + 1];
float x3 = vertices[t3], y3 = vertices[t3 + 1];
// If the base of the last triangle is the same as this triangle, check if they form a convex polygon (triangle fan).
bool merged = false;
if (fanBaseIndex == t1) {
size_t o = polygon->size() - 4;
Array<float> &p = *polygon;
int winding1 = winding(p[o], p[o + 1], p[o + 2], p[o + 3], x3, y3);
int winding2 = winding(x3, y3, p[0], p[1], p[2], p[3]);
if (winding1 == lastwinding && winding2 == lastwinding) {
polygon->add(x3);
polygon->add(y3);
polygonIndices->add(t3);
merged = true;
}
}
// Otherwise make this triangle the new base.
if (!merged) {
if (polygon->size() > 0) {
convexPolygons.add(polygon);
convexPolygonsIndices.add(polygonIndices);
} else {
_polygonPool.free(polygon);
_polygonIndicesPool.free(polygonIndices);
}
polygon = _polygonPool.obtain();
polygon->clear();
polygon->add(x1);
polygon->add(y1);
polygon->add(x2);
polygon->add(y2);
polygon->add(x3);
polygon->add(y3);
polygonIndices = _polygonIndicesPool.obtain();
polygonIndices->clear();
polygonIndices->add(t1);
polygonIndices->add(t2);
polygonIndices->add(t3);
lastwinding = winding(x1, y1, x2, y2, x3, y3);
fanBaseIndex = t1;
}
}
if (polygon->size() > 0) {
convexPolygons.add(polygon);
convexPolygonsIndices.add(polygonIndices);
}
// Go through the list of polygons and try to merge the remaining triangles with the found triangle fans.
for (size_t i = 0, n = convexPolygons.size(); i < n; ++i) {
polygonIndices = convexPolygonsIndices[i];
if (polygonIndices->size() == 0) continue;
int firstIndex = (*polygonIndices)[0];
int lastIndex = (*polygonIndices)[polygonIndices->size() - 1];
polygon = convexPolygons[i];
size_t o = polygon->size() - 4;
Array<float> &p = *polygon;
float prevPrevX = p[o], prevPrevY = p[o + 1];
float prevX = p[o + 2], prevY = p[o + 3];
float firstX = p[0], firstY = p[1];
float secondX = p[2], secondY = p[3];
int winding0 = winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY);
for (size_t ii = 0; ii < n; ++ii) {
if (ii == i) continue;
Array<int> *otherIndicesP = convexPolygonsIndices[ii];
Array<int> &otherIndices = *otherIndicesP;
if (otherIndices.size() != 3) continue;
int otherFirstIndex = otherIndices[0];
int otherSecondIndex = otherIndices[1];
int otherLastIndex = otherIndices[2];
Array<float> *otherPolyP = convexPolygons[ii];
Array<float> &otherPoly = *otherPolyP;
float x3 = otherPoly[otherPoly.size() - 2], y3 = otherPoly[otherPoly.size() - 1];
if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) continue;
int winding1 = winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3);
int winding2 = winding(x3, y3, firstX, firstY, secondX, secondY);
if (winding1 == winding0 && winding2 == winding0) {
otherPoly.clear();
otherIndices.clear();
polygon->add(x3);
polygon->add(y3);
polygonIndices->add(otherLastIndex);
prevPrevX = prevX;
prevPrevY = prevY;
prevX = x3;
prevY = y3;
ii = 0;
}
}
}
// Remove empty polygons that resulted from the merge step above.
for (int i = (int) convexPolygons.size() - 1; i >= 0; --i) {
polygon = convexPolygons[i];
if (polygon->size() == 0) {
convexPolygons.removeAt(i);
_polygonPool.free(polygon);
polygonIndices = convexPolygonsIndices[i];
convexPolygonsIndices.removeAt(i);
_polygonIndicesPool.free(polygonIndices);
}
}
return convexPolygons;
}
bool Triangulator::isConcave(int index, int vertexCount, Array<float> &vertices, Array<int> &indices) {
int previous = indices[(vertexCount + index - 1) % vertexCount] << 1;
int current = indices[index] << 1;
int next = indices[(index + 1) % vertexCount] << 1;
return !positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next], vertices[next + 1]);
}
bool Triangulator::positiveArea(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0;
}
int Triangulator::winding(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
float px = p2x - p1x, py = p2y - p1y;
return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1;
}

View File

@ -1,40 +0,0 @@
/******************************************************************************
* 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 <spine/Update.h>
using namespace spine;
RTTI_IMPL_NOPARENT(Update)
Update::Update() {
}
Update::~Update() {
}

View File

@ -1,166 +0,0 @@
/******************************************************************************
* 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 <spine/VertexAttachment.h>
#include <spine/Slot.h>
#include <spine/Bone.h>
#include <spine/Skeleton.h>
using namespace spine;
RTTI_IMPL(VertexAttachment, Attachment)
VertexAttachment::VertexAttachment(const String &name) : Attachment(name), _worldVerticesLength(0), _id(getNextID()) {
}
VertexAttachment::~VertexAttachment() {
}
void VertexAttachment::computeWorldVertices(Skeleton &skeleton, Slot &slot, size_t start, size_t count, Array<float> &worldVertices, size_t offset,
size_t stride) {
computeWorldVertices(skeleton, slot, start, count, worldVertices.buffer(), offset, stride);
}
void VertexAttachment::computeWorldVertices(Skeleton &skeleton, Slot &slot, size_t start, size_t count, float *worldVertices, size_t offset,
size_t stride) {
count = offset + (count >> 1) * stride;
Array<float> *deformArray = &slot.getAppliedPose().getDeform();
Array<float> *vertices = &_vertices;
Array<int> &bones = _bones;
if (bones.size() == 0) {
if (deformArray->size() > 0) vertices = deformArray;
BonePose &bone = slot.getBone().getAppliedPose();
float x = bone.getWorldX();
float y = bone.getWorldY();
float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD();
for (size_t vv = start, w = offset; w < count; vv += 2, w += stride) {
float vx = (*vertices)[vv];
float vy = (*vertices)[vv + 1];
worldVertices[w] = vx * a + vy * b + x;
worldVertices[w + 1] = vx * c + vy * d + y;
}
return;
}
int v = 0, skip = 0;
for (size_t i = 0; i < start; i += 2) {
int n = (int) bones[v];
v += n + 1;
skip += n;
}
Array<Bone *> &skeletonBones = skeleton.getBones();
if (deformArray->size() == 0) {
for (size_t w = offset, b = skip * 3; w < count; w += stride) {
float wx = 0, wy = 0;
int n = (int) bones[v++];
n += v;
for (; v < n; v++, b += 3) {
Bone *boneP = skeletonBones[bones[v]];
BonePose &bonePose = boneP->getAppliedPose();
float vx = (*vertices)[b];
float vy = (*vertices)[b + 1];
float weight = (*vertices)[b + 2];
wx += (vx * bonePose.getA() + vy * bonePose.getB() + bonePose.getWorldX()) * weight;
wy += (vx * bonePose.getC() + vy * bonePose.getD() + bonePose.getWorldY()) * weight;
}
worldVertices[w] = wx;
worldVertices[w + 1] = wy;
}
} else {
for (size_t w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) {
float wx = 0, wy = 0;
int n = (int) bones[v++];
n += v;
for (; v < n; v++, b += 3, f += 2) {
Bone *boneP = skeletonBones[bones[v]];
BonePose &bonePose = boneP->getAppliedPose();
float vx = (*vertices)[b] + (*deformArray)[f];
float vy = (*vertices)[b + 1] + (*deformArray)[f + 1];
float weight = (*vertices)[b + 2];
wx += (vx * bonePose.getA() + vy * bonePose.getB() + bonePose.getWorldX()) * weight;
wy += (vx * bonePose.getC() + vy * bonePose.getD() + bonePose.getWorldY()) * weight;
}
worldVertices[w] = wx;
worldVertices[w + 1] = wy;
}
}
}
int VertexAttachment::getId() {
return _id;
}
Array<int> &VertexAttachment::getBones() {
return _bones;
}
void VertexAttachment::setBones(Array<int> &bones) {
_bones.clearAndAddAll(bones);
}
Array<float> &VertexAttachment::getVertices() {
return _vertices;
}
void VertexAttachment::setVertices(Array<float> &vertices) {
_vertices.clearAndAddAll(vertices);
}
size_t VertexAttachment::getWorldVerticesLength() {
return _worldVerticesLength;
}
void VertexAttachment::setWorldVerticesLength(size_t inValue) {
_worldVerticesLength = inValue;
}
Attachment *VertexAttachment::getTimelineAttachment() {
return Attachment::getTimelineAttachment();
}
void VertexAttachment::setTimelineAttachment(Attachment *attachment) {
Attachment::setTimelineAttachment(attachment);
}
int VertexAttachment::getNextID() {
static int nextID = 0;
return nextID++;
}
void VertexAttachment::copyTo(VertexAttachment &other) {
other._bones.clearAndAddAll(this->_bones);
other._vertices.clearAndAddAll(this->_vertices);
other._worldVerticesLength = this->_worldVerticesLength;
other.setTimelineAttachment(this->getTimelineAttachment());
}