mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-10 00:58:43 +08:00
Merge branch '3.6' into 3.7-beta
This commit is contained in:
commit
66070960a5
@ -22,11 +22,11 @@ void RegisterMemoryLeakDetector()
|
||||
{
|
||||
// Register our malloc and free functions to track memory leaks
|
||||
#ifdef KANJI_MEMTRACE
|
||||
_setDebugMalloc(_kanjimalloc);
|
||||
_spSetDebugMalloc(_kanjimalloc);
|
||||
#endif
|
||||
_setMalloc(_kanjimalloc);
|
||||
_setRealloc(_kanjirealloc);
|
||||
_setFree(_kanjifree);
|
||||
_spSetMalloc(_kanjimalloc);
|
||||
_spSetRealloc(_kanjirealloc);
|
||||
_spSetFree(_kanjifree);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@ -74,6 +74,6 @@ extern "C" { // probably unnecessary
|
||||
}
|
||||
|
||||
char* _spUtil_readFile(const char* path, int* length) {
|
||||
return _readFile(path, length);
|
||||
return _spReadFile(path, length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Our memory system is thread-safe, but instead of linking massive libraries,
|
||||
// we attempt to use C++11 std::mutex.
|
||||
#ifdef USE_CPP11_MUTEX
|
||||
#ifdef USE_CPP11_MUTEX_DISABLED
|
||||
#include <mutex>
|
||||
typedef std::recursive_mutex KSysLock; // rentrant
|
||||
struct KAutoLock {
|
||||
@ -300,4 +300,4 @@ size_t KMemoryAllocated()
|
||||
size += info.size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,29 +92,65 @@ void Json_dispose (Json *c) {
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static const char* parse_number (Json *item, const char* num) {
|
||||
char * endptr;
|
||||
float n;
|
||||
double result = 0.0;
|
||||
int negative = 0;
|
||||
char* ptr = (char*)num;
|
||||
|
||||
/* Using strtod and strtof is slightly more permissive than RFC4627,
|
||||
* accepting for example hex-encoded floating point, but either
|
||||
* is often leagues faster than any manual implementation.
|
||||
*
|
||||
* We also already know that this starts with [-0-9] from parse_value.
|
||||
*/
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
n = strtof(num, &endptr);
|
||||
#else
|
||||
n = (float)strtod( num, &endptr );
|
||||
#endif
|
||||
/* ignore errno's ERANGE, which returns +/-HUGE_VAL */
|
||||
/* n is 0 on any other error */
|
||||
if (*ptr == '-') {
|
||||
negative = -1;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
if (endptr != num) {
|
||||
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;
|
||||
int n = 0;
|
||||
++ptr;
|
||||
|
||||
if (*ptr == '-') {
|
||||
expNegative = -1;
|
||||
++ptr;
|
||||
} else if (*ptr == '+') {
|
||||
++ptr;
|
||||
}
|
||||
|
||||
while (*ptr >= '0' && *ptr <= '9') {
|
||||
exponent = (exponent * 10.0) + (*ptr - '0');
|
||||
++ptr;
|
||||
++n;
|
||||
}
|
||||
|
||||
if (expNegative)
|
||||
result = result / POW(10, exponent);
|
||||
else
|
||||
result = result * POW(10, exponent);
|
||||
}
|
||||
|
||||
if (ptr != num) {
|
||||
/* Parse success, number found. */
|
||||
item->valueFloat = n;
|
||||
item->valueInt = (int)n;
|
||||
item->valueFloat = result;
|
||||
item->valueInt = (int)result;
|
||||
item->type = Json_Number;
|
||||
return endptr;
|
||||
return ptr;
|
||||
} else {
|
||||
/* Parse failure, ep is set. */
|
||||
ep = num;
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
|
||||
#include <spine/SkeletonJson.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include "Json.h"
|
||||
#include <spine/extension.h>
|
||||
#include <spine/AtlasAttachmentLoader.h>
|
||||
@ -579,25 +578,14 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
|
||||
int i, ii;
|
||||
spSkeletonData* skeletonData;
|
||||
Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *slots, *skins, *animations, *events;
|
||||
char* oldLocale;
|
||||
_spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self);
|
||||
|
||||
FREE(self->error);
|
||||
CONST_CAST(char*, self->error) = 0;
|
||||
internal->linkedMeshCount = 0;
|
||||
|
||||
#ifndef __ANDROID__
|
||||
oldLocale = strdup(setlocale(LC_NUMERIC, NULL));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#endif
|
||||
|
||||
root = Json_create(json);
|
||||
|
||||
#ifndef __ANDROID__
|
||||
setlocale(LC_NUMERIC, oldLocale);
|
||||
free(oldLocale);
|
||||
#endif
|
||||
|
||||
if (!root) {
|
||||
_spSkeletonJson_setError(self, 0, "Invalid skeleton JSON: ", Json_getError());
|
||||
return 0;
|
||||
|
||||
@ -36,12 +36,35 @@
|
||||
#include <spine/Cocos2dAttachmentLoader.h>
|
||||
#include <algorithm>
|
||||
|
||||
#define INITIAL_WORLD_VERTICES_LENGTH 1000
|
||||
// Used for transforming attachments for bounding boxes & debug rendering
|
||||
static float* worldVertices = nullptr;
|
||||
static size_t worldVerticesLength = 0;
|
||||
|
||||
void ensureWorldVerticesCapacity(size_t capacity) {
|
||||
if (worldVerticesLength < capacity) {
|
||||
float* newWorldVertices = new float[capacity];
|
||||
memcpy(newWorldVertices, worldVertices, capacity * sizeof(float));
|
||||
delete[] worldVertices;
|
||||
worldVertices = newWorldVertices;
|
||||
worldVerticesLength = capacity;
|
||||
}
|
||||
}
|
||||
|
||||
USING_NS_CC;
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
namespace spine {
|
||||
|
||||
void SkeletonRenderer::destroyScratchBuffers() {
|
||||
if (worldVertices) {
|
||||
delete[] worldVertices;
|
||||
worldVertices = nullptr;
|
||||
worldVerticesLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SkeletonRenderer* SkeletonRenderer::createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) {
|
||||
SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData);
|
||||
node->autorelease();
|
||||
@ -61,7 +84,10 @@ SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonD
|
||||
}
|
||||
|
||||
void SkeletonRenderer::initialize () {
|
||||
_worldVertices = new float[1000]; // Max number of vertices per mesh.
|
||||
if (!worldVertices) {
|
||||
worldVertices = new float[INITIAL_WORLD_VERTICES_LENGTH];
|
||||
worldVerticesLength = INITIAL_WORLD_VERTICES_LENGTH;
|
||||
}
|
||||
|
||||
_clipper = spSkeletonClipping_create();
|
||||
|
||||
@ -131,8 +157,7 @@ SkeletonRenderer::~SkeletonRenderer () {
|
||||
if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data);
|
||||
spSkeleton_dispose(_skeleton);
|
||||
if (_atlas) spAtlas_dispose(_atlas);
|
||||
if (_attachmentLoader) spAttachmentLoader_dispose(_attachmentLoader);
|
||||
delete [] _worldVertices;
|
||||
if (_attachmentLoader) spAttachmentLoader_dispose(_attachmentLoader);
|
||||
spSkeletonClipping_dispose(_clipper);
|
||||
}
|
||||
|
||||
@ -613,11 +638,11 @@ void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uin
|
||||
spSlot* slot = _skeleton->drawOrder[i];
|
||||
if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue;
|
||||
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
|
||||
spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices, 0, 2);
|
||||
points[0] = Vec2(_worldVertices[0], _worldVertices[1]);
|
||||
points[1] = Vec2(_worldVertices[2], _worldVertices[3]);
|
||||
points[2] = Vec2(_worldVertices[4], _worldVertices[5]);
|
||||
points[3] = Vec2(_worldVertices[6], _worldVertices[7]);
|
||||
spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices, 0, 2);
|
||||
points[0] = Vec2(worldVertices[0], worldVertices[1]);
|
||||
points[1] = Vec2(worldVertices[2], worldVertices[3]);
|
||||
points[2] = Vec2(worldVertices[4], worldVertices[5]);
|
||||
points[3] = Vec2(worldVertices[6], worldVertices[7]);
|
||||
drawNode->drawPoly(points, 4, true, Color4F::BLUE);
|
||||
}
|
||||
}
|
||||
@ -645,12 +670,13 @@ void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uin
|
||||
for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) {
|
||||
spSlot* slot = _skeleton->drawOrder[i];
|
||||
if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_MESH) continue;
|
||||
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
|
||||
spVertexAttachment_computeWorldVertices(SUPER(attachment), slot, 0, attachment->super.worldVerticesLength, _worldVertices, 0, 2);
|
||||
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
|
||||
ensureWorldVerticesCapacity(attachment->super.worldVerticesLength);
|
||||
spVertexAttachment_computeWorldVertices(SUPER(attachment), slot, 0, attachment->super.worldVerticesLength, worldVertices, 0, 2);
|
||||
for (int ii = 0; ii < attachment->trianglesCount;) {
|
||||
Vec2 v1(_worldVertices + (attachment->triangles[ii++] * 2));
|
||||
Vec2 v2(_worldVertices + (attachment->triangles[ii++] * 2));
|
||||
Vec2 v3(_worldVertices + (attachment->triangles[ii++] * 2));
|
||||
Vec2 v1(worldVertices + (attachment->triangles[ii++] * 2));
|
||||
Vec2 v2(worldVertices + (attachment->triangles[ii++] * 2));
|
||||
Vec2 v3(worldVertices + (attachment->triangles[ii++] * 2));
|
||||
drawNode->drawLine(v1, v2, Color4F::YELLOW);
|
||||
drawNode->drawLine(v2, v3, Color4F::YELLOW);
|
||||
drawNode->drawLine(v3, v1, Color4F::YELLOW);
|
||||
@ -680,16 +706,17 @@ Rect SkeletonRenderer::getBoundingBox () const {
|
||||
int verticesCount;
|
||||
if (slot->attachment->type == SP_ATTACHMENT_REGION) {
|
||||
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
|
||||
spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices, 0, 2);
|
||||
spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices, 0, 2);
|
||||
verticesCount = 8;
|
||||
} else if (slot->attachment->type == SP_ATTACHMENT_MESH) {
|
||||
spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment;
|
||||
spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, _worldVertices, 0, 2);
|
||||
ensureWorldVerticesCapacity(mesh->super.worldVerticesLength);
|
||||
spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, worldVertices, 0, 2);
|
||||
verticesCount = mesh->super.worldVerticesLength;
|
||||
} else
|
||||
continue;
|
||||
for (int ii = 0; ii < verticesCount; ii += 2) {
|
||||
float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY;
|
||||
float x = worldVertices[ii] * scaleX, y = worldVertices[ii + 1] * scaleY;
|
||||
minX = min(minX, x);
|
||||
minY = min(minY, y);
|
||||
maxX = max(maxX, x);
|
||||
|
||||
@ -108,6 +108,9 @@ public:
|
||||
virtual const cocos2d::BlendFunc& getBlendFunc () const override;
|
||||
virtual void setOpacityModifyRGB (bool value) override;
|
||||
virtual bool isOpacityModifyRGB () const override;
|
||||
|
||||
// Frees global memory used for temporay vertex transformations.
|
||||
static void destroyScratchBuffers();
|
||||
|
||||
CC_CONSTRUCTOR_ACCESS:
|
||||
SkeletonRenderer ();
|
||||
@ -136,7 +139,6 @@ protected:
|
||||
spAttachmentLoader* _attachmentLoader;
|
||||
cocos2d::CustomCommand _debugCommand;
|
||||
cocos2d::BlendFunc _blendFunc;
|
||||
float* _worldVertices;
|
||||
bool _premultipliedAlpha;
|
||||
spSkeleton* _skeleton;
|
||||
float _timeScale;
|
||||
|
||||
@ -66,6 +66,7 @@ public class SkeletonRenderer {
|
||||
if (vertexEffect != null) vertexEffect.begin(skeleton);
|
||||
|
||||
boolean premultipliedAlpha = this.premultipliedAlpha;
|
||||
BlendMode blendMode = null;
|
||||
float[] vertices = this.vertices.items;
|
||||
Color skeletonColor = skeleton.color;
|
||||
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
|
||||
@ -79,6 +80,17 @@ public class SkeletonRenderer {
|
||||
Color color = region.getColor(), slotColor = slot.getColor();
|
||||
float alpha = a * slotColor.a * color.a * 255;
|
||||
float multiplier = premultipliedAlpha ? alpha : 255;
|
||||
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
if (slotBlendMode == BlendMode.additive && premultipliedAlpha) {
|
||||
slotBlendMode = BlendMode.normal;
|
||||
alpha = 0;
|
||||
}
|
||||
blendMode = slotBlendMode;
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
}
|
||||
|
||||
float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
|
||||
| ((int)(b * slotColor.b * color.b * multiplier) << 16) //
|
||||
| ((int)(g * slotColor.g * color.g * multiplier) << 8) //
|
||||
@ -92,8 +104,6 @@ public class SkeletonRenderer {
|
||||
|
||||
if (vertexEffect != null) applyVertexEffect(vertices, 20, 5, c, 0);
|
||||
|
||||
BlendMode blendMode = slot.data.getBlendMode();
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
batch.draw(region.getRegion().getTexture(), vertices, 0, 20);
|
||||
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
@ -101,9 +111,8 @@ public class SkeletonRenderer {
|
||||
continue;
|
||||
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
throw new RuntimeException(
|
||||
"SkeletonRenderer#draw(PolygonSpriteBatch, Skeleton) or #draw(TwoColorPolygonBatch, Skeleton) must be used to "
|
||||
+ "render meshes.");
|
||||
throw new RuntimeException(batch.getClass().getSimpleName()
|
||||
+ " cannot render meshes, PolygonSpriteBatch or TwoColorPolygonBatch is required.");
|
||||
|
||||
} else if (attachment instanceof SkeletonAttachment) {
|
||||
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
||||
@ -175,17 +184,22 @@ public class SkeletonRenderer {
|
||||
Color slotColor = slot.getColor();
|
||||
float alpha = a * slotColor.a * color.a * 255;
|
||||
float multiplier = premultipliedAlpha ? alpha : 255;
|
||||
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
if (slotBlendMode == BlendMode.additive && premultipliedAlpha) {
|
||||
slotBlendMode = BlendMode.normal;
|
||||
alpha = 0;
|
||||
}
|
||||
blendMode = slotBlendMode;
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
}
|
||||
|
||||
float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
|
||||
| ((int)(b * slotColor.b * color.b * multiplier) << 16) //
|
||||
| ((int)(g * slotColor.g * color.g * multiplier) << 8) //
|
||||
| (int)(r * slotColor.r * color.r * multiplier));
|
||||
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
}
|
||||
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTriangles(vertices, verticesLength, triangles, triangles.length, uvs, c, 0, false);
|
||||
FloatArray clippedVertices = clipper.getClippedVertices();
|
||||
@ -288,6 +302,17 @@ public class SkeletonRenderer {
|
||||
Color lightColor = slot.getColor();
|
||||
float alpha = a * lightColor.a * color.a * 255;
|
||||
float multiplier = premultipliedAlpha ? alpha : 255;
|
||||
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
if (slotBlendMode == BlendMode.additive && premultipliedAlpha) {
|
||||
slotBlendMode = BlendMode.normal;
|
||||
alpha = 0;
|
||||
}
|
||||
blendMode = slotBlendMode;
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
}
|
||||
|
||||
float red = r * color.r * multiplier;
|
||||
float green = g * color.g * multiplier;
|
||||
float blue = b * color.b * multiplier;
|
||||
@ -301,12 +326,6 @@ public class SkeletonRenderer {
|
||||
| (int)(green * darkColor.g) << 8 //
|
||||
| (int)(red * darkColor.r));
|
||||
|
||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||
if (slotBlendMode != blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||
}
|
||||
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTriangles(vertices, verticesLength, triangles, triangles.length, uvs, light, dark, true);
|
||||
FloatArray clippedVertices = clipper.getClippedVertices();
|
||||
|
||||
@ -253,7 +253,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
}
|
||||
|
||||
public void render () {
|
||||
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
|
||||
Gdx.gl.glClearColor(112 / 255f, 111 / 255f, 118 / 255f, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
float delta = Gdx.graphics.getDeltaTime();
|
||||
|
||||
@ -44,13 +44,13 @@ The Spine SFML example works on Windows, Linux and Mac OS X.
|
||||
The entire example code is contained in [main.cpp](example/main.cpp#L61)
|
||||
|
||||
### Linux
|
||||
1. Install the SFML dependencies, e.g. on Ubuntu/Debian via `sudo apt-get install -y libpthread-stubs0-dev libgl1-mesa-dev libx11-dev libxrandr-dev libfreetype6-dev libglew1.5-dev libjpeg8-dev libsndfile1-dev libopenal-dev libudev-dev libxcb-image0-dev libjpeg-dev libflac-dev`
|
||||
1. Install the SFML dependencies, e.g. on Ubuntu/Debian via `sudo apt install libsfml-dev`
|
||||
2. Install CMake, e.g. on Ubuntu/Debian via `sudo apt-get install -y cmake`
|
||||
3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it as a zip via the download button above.
|
||||
4. Open a terminal, and `cd` into the `spine-runtimes/spine-sfml` folder
|
||||
5. Type `mkdir build && cd build && cmake ../..` to generate Make files
|
||||
6. Type `make` to compile the example
|
||||
7. Run the example by `cd spine-sfml-example && ./spine-sfml-example`
|
||||
7. Run the example by `cd spine-sfml && ./spine-sfml-example`
|
||||
|
||||
### Mac OS X
|
||||
1. Install [Xcode](https://developer.apple.com/xcode/)
|
||||
|
||||
@ -457,7 +457,7 @@ namespace Spine.Unity {
|
||||
var skeleton = instruction.skeleton;
|
||||
var drawOrderItems = skeleton.drawOrder.Items;
|
||||
|
||||
Color32 color;
|
||||
Color32 color = default(Color32);
|
||||
float skeletonA = skeleton.a * 255, skeletonR = skeleton.r, skeletonG = skeleton.g, skeletonB = skeleton.b;
|
||||
Vector2 meshBoundsMin = this.meshBoundsMin, meshBoundsMax = this.meshBoundsMax;
|
||||
|
||||
@ -661,7 +661,7 @@ namespace Spine.Unity {
|
||||
}
|
||||
|
||||
// Populate Verts
|
||||
Color32 color;
|
||||
Color32 color = default(Color32);
|
||||
|
||||
int vertexIndex = 0;
|
||||
var tempVerts = this.tempVerts;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user