mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-09 08:38:43 +08:00
[flutter] skeleton drawable, vertices creation
This commit is contained in:
parent
c1d9a9e23e
commit
887d77ef63
@ -84,11 +84,12 @@ namespace spine {
|
||||
TextureWrap vWrap;
|
||||
int width, height;
|
||||
bool pma;
|
||||
int index;
|
||||
|
||||
explicit AtlasPage(const String &inName) : name(inName), format(Format_RGBA8888),
|
||||
minFilter(TextureFilter_Nearest),
|
||||
magFilter(TextureFilter_Nearest), uWrap(TextureWrap_ClampToEdge),
|
||||
vWrap(TextureWrap_ClampToEdge), width(0), height(0), pma(false) {
|
||||
vWrap(TextureWrap_ClampToEdge), width(0), height(0), pma(false), index(0) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -286,6 +286,7 @@ void Atlas::load(const char *begin, int length, const char *dir, bool createText
|
||||
} else {
|
||||
page->texturePath = String(path, true);
|
||||
}
|
||||
page->index = _pages.size();
|
||||
_pages.add(page);
|
||||
} else {
|
||||
AtlasRegion *region = new (__FILE__, __LINE__) AtlasRegion();
|
||||
|
||||
6
spine-flutter/example/assets/skeleton.atlas
Normal file
6
spine-flutter/example/assets/skeleton.atlas
Normal file
@ -0,0 +1,6 @@
|
||||
skeleton.png
|
||||
size:188,198
|
||||
filter:Linear,Linear
|
||||
pma:true
|
||||
Screenshot 2022-08-19 at 13.45.53
|
||||
bounds:2,2,184,194
|
||||
40
spine-flutter/example/assets/skeleton.json
Normal file
40
spine-flutter/example/assets/skeleton.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"skeleton": {
|
||||
"hash": "EzIWQLMq9sw",
|
||||
"spine": "4.1.08",
|
||||
"x": -92,
|
||||
"y": -97,
|
||||
"width": 184,
|
||||
"height": 194,
|
||||
"images": "",
|
||||
"audio": ""
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
"name": "root"
|
||||
}
|
||||
],
|
||||
"slots": [
|
||||
{
|
||||
"name": "image",
|
||||
"bone": "root",
|
||||
"attachment": "Screenshot 2022-08-19 at 13.45.53"
|
||||
}
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"name": "default",
|
||||
"attachments": {
|
||||
"image": {
|
||||
"Screenshot 2022-08-19 at 13.45.53": {
|
||||
"width": 184,
|
||||
"height": 194
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"animations": {
|
||||
"animation": {}
|
||||
}
|
||||
}
|
||||
BIN
spine-flutter/example/assets/skeleton.png
Normal file
BIN
spine-flutter/example/assets/skeleton.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@ -27,9 +27,13 @@ class _MyAppState extends State<MyApp> {
|
||||
}
|
||||
|
||||
void loadSkeleton() async {
|
||||
final atlas = await spine_flutter.loadAtlas(rootBundle, "assets/spineboy.atlas");
|
||||
final skeletonData = spine_flutter.loadSkeletonDataJson(atlas, await rootBundle.loadString("assets/spineboy-pro.json"));
|
||||
final skeletonDataBinary = spine_flutter.loadSkeletonDataBinary(atlas, await rootBundle.load("assets/spineboy-pro.skel"));
|
||||
final atlas = await spine_flutter.loadAtlas(rootBundle, "assets/skeleton.atlas");
|
||||
final skeletonData = spine_flutter.loadSkeletonDataJson(atlas, await rootBundle.loadString("assets/skeleton.json"));
|
||||
// final skeletonDataBinary = spine_flutter.loadSkeletonDataBinary(atlas, await rootBundle.load("assets/spineboy-pro.skel"));
|
||||
final skeletonDrawable = spine_flutter.createSkeletonDrawable(skeletonData);
|
||||
spine_flutter.updateSkeletonDrawable(skeletonDrawable, 0.016);
|
||||
final renderCommands = spine_flutter.renderSkeletonDrawable(skeletonDrawable);
|
||||
print(renderCommands[0].vertices);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
@ -60,6 +62,46 @@ Pointer<spine_skeleton_data> loadSkeletonDataBinary(Pointer<spine_atlas> atlas,
|
||||
return skeletonData;
|
||||
}
|
||||
|
||||
Pointer<spine_skeleton_drawable> createSkeletonDrawable(Pointer<spine_skeleton_data> skeletonData) {
|
||||
return _bindings.spine_skeleton_drawable_create(skeletonData);
|
||||
}
|
||||
|
||||
void updateSkeletonDrawable(Pointer<spine_skeleton_drawable> drawable, double deltaTime) {
|
||||
_bindings.spine_skeleton_drawable_update(drawable, deltaTime);
|
||||
}
|
||||
|
||||
class RenderCommand {
|
||||
late Vertices vertices;
|
||||
late int atlasPageIndex;
|
||||
RenderCommand? next;
|
||||
|
||||
RenderCommand(Pointer<spine_render_command> nativeCmd) {
|
||||
atlasPageIndex = nativeCmd.ref.atlasPage;
|
||||
int numVertices = nativeCmd.ref.numVertices;
|
||||
int numIndices = nativeCmd.ref.numIndices;
|
||||
// We pass the native data as views directly to Vertices.raw. According to the sources, the data
|
||||
// is copied, so it doesn't matter that we free up the underlying memory on the next
|
||||
// render call. See the implementation of Vertices.raw() here:
|
||||
// https://github.com/flutter/engine/blob/5c60785b802ad2c8b8899608d949342d5c624952/lib/ui/painting/vertices.cc#L21
|
||||
vertices = Vertices.raw(VertexMode.triangles,
|
||||
nativeCmd.ref.positions.asTypedList(numVertices * 2),
|
||||
textureCoordinates: nativeCmd.ref.uvs.asTypedList(numVertices * 2),
|
||||
colors: nativeCmd.ref.colors.asTypedList(numVertices),
|
||||
indices: nativeCmd.ref.indices.asTypedList(numIndices));
|
||||
}
|
||||
}
|
||||
|
||||
List<RenderCommand> renderSkeletonDrawable(Pointer<spine_skeleton_drawable> drawable) {
|
||||
Pointer<spine_render_command> nativeCmd = _bindings.spine_skeleton_drawable_render(drawable);
|
||||
List<RenderCommand> commands = [];
|
||||
while(nativeCmd.address != nullptr.address) {
|
||||
commands.add(RenderCommand(nativeCmd));
|
||||
nativeCmd = nativeCmd.ref.next;
|
||||
}
|
||||
return commands;
|
||||
|
||||
}
|
||||
|
||||
const String _libName = 'spine_flutter';
|
||||
|
||||
final DynamicLibrary _dylib = () {
|
||||
|
||||
@ -129,6 +129,76 @@ class SpineFlutterBindings {
|
||||
'spine_skeleton_data_dispose');
|
||||
late final _spine_skeleton_data_dispose = _spine_skeleton_data_disposePtr
|
||||
.asFunction<void Function(ffi.Pointer<spine_skeleton_data>)>();
|
||||
|
||||
ffi.Pointer<spine_skeleton_drawable> spine_skeleton_drawable_create(
|
||||
ffi.Pointer<spine_skeleton_data> skeletonData,
|
||||
) {
|
||||
return _spine_skeleton_drawable_create(
|
||||
skeletonData,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_skeleton_drawable_createPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<spine_skeleton_drawable> Function(
|
||||
ffi.Pointer<spine_skeleton_data>)>>(
|
||||
'spine_skeleton_drawable_create');
|
||||
late final _spine_skeleton_drawable_create =
|
||||
_spine_skeleton_drawable_createPtr.asFunction<
|
||||
ffi.Pointer<spine_skeleton_drawable> Function(
|
||||
ffi.Pointer<spine_skeleton_data>)>();
|
||||
|
||||
void spine_skeleton_drawable_update(
|
||||
ffi.Pointer<spine_skeleton_drawable> drawable,
|
||||
double deltaTime,
|
||||
) {
|
||||
return _spine_skeleton_drawable_update(
|
||||
drawable,
|
||||
deltaTime,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_skeleton_drawable_updatePtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(ffi.Pointer<spine_skeleton_drawable>,
|
||||
ffi.Float)>>('spine_skeleton_drawable_update');
|
||||
late final _spine_skeleton_drawable_update =
|
||||
_spine_skeleton_drawable_updatePtr.asFunction<
|
||||
void Function(ffi.Pointer<spine_skeleton_drawable>, double)>();
|
||||
|
||||
ffi.Pointer<spine_render_command> spine_skeleton_drawable_render(
|
||||
ffi.Pointer<spine_skeleton_drawable> drawable,
|
||||
) {
|
||||
return _spine_skeleton_drawable_render(
|
||||
drawable,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_skeleton_drawable_renderPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<spine_render_command> Function(
|
||||
ffi.Pointer<spine_skeleton_drawable>)>>(
|
||||
'spine_skeleton_drawable_render');
|
||||
late final _spine_skeleton_drawable_render =
|
||||
_spine_skeleton_drawable_renderPtr.asFunction<
|
||||
ffi.Pointer<spine_render_command> Function(
|
||||
ffi.Pointer<spine_skeleton_drawable>)>();
|
||||
|
||||
void spine_skeleton_drawable_dispose(
|
||||
ffi.Pointer<spine_skeleton_drawable> drawable,
|
||||
) {
|
||||
return _spine_skeleton_drawable_dispose(
|
||||
drawable,
|
||||
);
|
||||
}
|
||||
|
||||
late final _spine_skeleton_drawable_disposePtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(ffi.Pointer<spine_skeleton_drawable>)>>(
|
||||
'spine_skeleton_drawable_dispose');
|
||||
late final _spine_skeleton_drawable_dispose =
|
||||
_spine_skeleton_drawable_disposePtr
|
||||
.asFunction<void Function(ffi.Pointer<spine_skeleton_drawable>)>();
|
||||
}
|
||||
|
||||
class spine_atlas extends ffi.Struct {
|
||||
@ -147,3 +217,42 @@ class spine_skeleton_data extends ffi.Struct {
|
||||
|
||||
external ffi.Pointer<ffi.Int8> error;
|
||||
}
|
||||
|
||||
abstract class spine_blend_mode {
|
||||
static const int SPINE_BLEND_MODE_NORMAL = 0;
|
||||
static const int SPINE_BLEND_MODE_ADDITIVE = 1;
|
||||
static const int SPINE_BLEND_MODE_MULTIPLY = 2;
|
||||
static const int SPINE_BLEND_MODE_SCREEN = 3;
|
||||
}
|
||||
|
||||
class spine_render_command extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Float> positions;
|
||||
|
||||
external ffi.Pointer<ffi.Float> uvs;
|
||||
|
||||
external ffi.Pointer<ffi.Int32> colors;
|
||||
|
||||
@ffi.Int32()
|
||||
external int numVertices;
|
||||
|
||||
external ffi.Pointer<ffi.Uint16> indices;
|
||||
|
||||
@ffi.Int32()
|
||||
external int numIndices;
|
||||
|
||||
@ffi.Int32()
|
||||
external int atlasPage;
|
||||
|
||||
@ffi.Int32()
|
||||
external int blendMode;
|
||||
|
||||
external ffi.Pointer<spine_render_command> next;
|
||||
}
|
||||
|
||||
class spine_skeleton_drawable extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Void> skeleton;
|
||||
|
||||
external ffi.Pointer<ffi.Void> animationState;
|
||||
|
||||
external ffi.Pointer<spine_render_command> renderCommand;
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ FFI_PLUGIN_EXPORT int32_t spine_minor_version() {
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT spine_atlas* spine_atlas_load(const char *atlasData) {
|
||||
if (!atlasData) return nullptr;
|
||||
int length = strlen(atlasData);
|
||||
auto atlas = new Atlas(atlasData, length, "", (TextureLoader*)nullptr, false);
|
||||
spine_atlas *result = SpineExtension::calloc<spine_atlas>(1, __FILE__, __LINE__);
|
||||
@ -36,6 +37,9 @@ FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) {
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT spine_skeleton_data *spine_skeleton_data_load_json(spine_atlas *atlas, const char *skeletonData) {
|
||||
if (!atlas) return nullptr;
|
||||
if (!atlas->atlas) return nullptr;
|
||||
if (!skeletonData) return nullptr;
|
||||
SkeletonJson json((Atlas*)atlas->atlas);
|
||||
SkeletonData *data = json.readSkeletonData(skeletonData);
|
||||
spine_skeleton_data *result = SpineExtension::calloc<spine_skeleton_data>(1, __FILE__, __LINE__);
|
||||
@ -47,6 +51,10 @@ FFI_PLUGIN_EXPORT spine_skeleton_data *spine_skeleton_data_load_json(spine_atlas
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT spine_skeleton_data* spine_skeleton_data_load_binary(spine_atlas *atlas, const unsigned char *skeletonData, int32_t length) {
|
||||
if (!atlas) return nullptr;
|
||||
if (!atlas->atlas) return nullptr;
|
||||
if (!skeletonData) return nullptr;
|
||||
if (length <= 0) return nullptr;
|
||||
SkeletonBinary binary((Atlas*)atlas->atlas);
|
||||
SkeletonData *data = binary.readSkeletonData(skeletonData, length);
|
||||
spine_skeleton_data *result = SpineExtension::calloc<spine_skeleton_data>(1, __FILE__, __LINE__);
|
||||
@ -64,6 +72,180 @@ FFI_PLUGIN_EXPORT void spine_skeleton_data_dispose(spine_skeleton_data *skeleton
|
||||
SpineExtension::free(skeletonData, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT spine_skeleton_drawable *spine_skeleton_drawable_create(spine_skeleton_data *skeletonData) {
|
||||
spine_skeleton_drawable *drawable = SpineExtension::calloc<spine_skeleton_drawable>(1, __FILE__, __LINE__);
|
||||
drawable->skeleton = new Skeleton((SkeletonData*)skeletonData->skeletonData);
|
||||
drawable->animationState = new AnimationState(new AnimationStateData((SkeletonData*)skeletonData->skeletonData));
|
||||
return drawable;
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT void spine_skeleton_drawable_update(spine_skeleton_drawable *drawable, float deltaTime) {
|
||||
if (!drawable) return;
|
||||
if (!drawable->skeleton) return;
|
||||
if (!drawable->animationState) return;
|
||||
|
||||
Skeleton *skeleton = (Skeleton*)drawable->skeleton;
|
||||
AnimationState *animationState = (AnimationState*)drawable->animationState;
|
||||
animationState->update(deltaTime);
|
||||
animationState->apply(*skeleton);
|
||||
skeleton->updateWorldTransform();
|
||||
}
|
||||
|
||||
spine_render_command *spine_render_command_create(int32_t numVertices, int32_t numIndices, spine_blend_mode blendMode, int pageIndex) {
|
||||
spine_render_command *cmd = SpineExtension::alloc<spine_render_command>(1, __FILE__, __LINE__);
|
||||
cmd->positions = SpineExtension::alloc<float>(numVertices * 2, __FILE__, __LINE__);
|
||||
cmd->uvs = SpineExtension::alloc<float>(numVertices * 2, __FILE__, __LINE__);
|
||||
cmd->colors = SpineExtension::alloc<int32_t>(numVertices, __FILE__, __LINE__);
|
||||
cmd->numVertices = numVertices;
|
||||
cmd->indices = SpineExtension::alloc<uint16_t>(numIndices, __FILE__, __LINE__);
|
||||
cmd->numIndices = numIndices;
|
||||
cmd->blendMode = blendMode;
|
||||
cmd->atlasPage = pageIndex;
|
||||
cmd->next = nullptr;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void spine_render_command_dispose(spine_render_command *cmd) {
|
||||
if (!cmd) return;
|
||||
if (cmd->positions) SpineExtension::free(cmd->positions, __FILE__, __LINE__);
|
||||
if (cmd->uvs) SpineExtension::free(cmd->uvs, __FILE__, __LINE__);
|
||||
if (cmd->colors) SpineExtension::free(cmd->colors, __FILE__, __LINE__);
|
||||
if (cmd->indices) SpineExtension::free(cmd->indices, __FILE__, __LINE__);
|
||||
SpineExtension::free(cmd, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT spine_render_command *spine_skeleton_drawable_render(spine_skeleton_drawable *drawable) {
|
||||
if (!drawable) return nullptr;
|
||||
if (!drawable->skeleton) return nullptr;
|
||||
|
||||
while (drawable->renderCommand) {
|
||||
spine_render_command *cmd = drawable->renderCommand;
|
||||
drawable->renderCommand = cmd->next;
|
||||
spine_render_command_dispose(cmd);
|
||||
}
|
||||
|
||||
Vector<unsigned short> quadIndices;
|
||||
quadIndices.add(0);
|
||||
quadIndices.add(1);
|
||||
quadIndices.add(2);
|
||||
quadIndices.add(2);
|
||||
quadIndices.add(3);
|
||||
quadIndices.add(0);
|
||||
Vector<float> worldVertices;
|
||||
SkeletonClipping clipper;
|
||||
Skeleton *skeleton = (Skeleton*)drawable->skeleton;
|
||||
spine_render_command *lastCommand = nullptr;
|
||||
|
||||
for (unsigned i = 0; i < skeleton->getSlots().size(); ++i) {
|
||||
Slot &slot = *skeleton->getDrawOrder()[i];
|
||||
Attachment *attachment = slot.getAttachment();
|
||||
if (!attachment) continue;
|
||||
|
||||
// Early out if the slot color is 0 or the bone is not active
|
||||
if (slot.getColor().a == 0 || !slot.getBone().isActive()) {
|
||||
clipper.clipEnd(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<float> *vertices = &worldVertices;
|
||||
int verticesCount = 0;
|
||||
Vector<float> *uvs = NULL;
|
||||
Vector<unsigned short> *indices;
|
||||
int indicesCount = 0;
|
||||
Color *attachmentColor;
|
||||
int pageIndex = -1;
|
||||
|
||||
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
||||
RegionAttachment *regionAttachment = (RegionAttachment *) attachment;
|
||||
attachmentColor = ®ionAttachment->getColor();
|
||||
|
||||
// Early out if the slot color is 0
|
||||
if (attachmentColor->a == 0) {
|
||||
clipper.clipEnd(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
worldVertices.setSize(8, 0);
|
||||
regionAttachment->computeWorldVertices(slot, worldVertices, 0, 2);
|
||||
verticesCount = 4;
|
||||
uvs = ®ionAttachment->getUVs();
|
||||
indices = &quadIndices;
|
||||
indicesCount = 6;
|
||||
pageIndex = ((AtlasRegion *) regionAttachment->getRendererObject())->page->index;
|
||||
|
||||
} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
|
||||
MeshAttachment *mesh = (MeshAttachment *) attachment;
|
||||
attachmentColor = &mesh->getColor();
|
||||
|
||||
// Early out if the slot color is 0
|
||||
if (attachmentColor->a == 0) {
|
||||
clipper.clipEnd(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
worldVertices.setSize(mesh->getWorldVerticesLength(), 0);
|
||||
pageIndex = ((AtlasRegion *) mesh->getRendererObject())->page->index;
|
||||
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices.buffer(), 0, 2);
|
||||
verticesCount = mesh->getWorldVerticesLength() >> 1;
|
||||
uvs = &mesh->getUVs();
|
||||
indices = &mesh->getTriangles();
|
||||
indicesCount = indices->size();
|
||||
|
||||
} else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
|
||||
ClippingAttachment *clip = (ClippingAttachment *) slot.getAttachment();
|
||||
clipper.clipStart(slot, clip);
|
||||
continue;
|
||||
} else
|
||||
continue;
|
||||
|
||||
uint8_t r = static_cast<uint8_t>(skeleton->getColor().r * slot.getColor().r * attachmentColor->r * 255);
|
||||
uint8_t g = static_cast<uint8_t>(skeleton->getColor().g * slot.getColor().g * attachmentColor->g * 255);
|
||||
uint8_t b = static_cast<uint8_t>(skeleton->getColor().b * slot.getColor().b * attachmentColor->b * 255);
|
||||
uint8_t a = static_cast<uint8_t>(skeleton->getColor().a * slot.getColor().a * attachmentColor->a * 255);
|
||||
uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTriangles(worldVertices, *indices, *uvs, 2);
|
||||
vertices = &clipper.getClippedVertices();
|
||||
verticesCount = clipper.getClippedVertices().size() >> 1;
|
||||
uvs = &clipper.getClippedUVs();
|
||||
indices = &clipper.getClippedTriangles();
|
||||
indicesCount = clipper.getClippedTriangles().size();
|
||||
}
|
||||
|
||||
spine_render_command *cmd = spine_render_command_create(verticesCount, indicesCount, (spine_blend_mode)slot.getData().getBlendMode(), pageIndex);
|
||||
|
||||
memcpy(cmd->positions, vertices->buffer(), (verticesCount << 2) * sizeof(float));
|
||||
memcpy(cmd->uvs, uvs->buffer(), (verticesCount << 2) * sizeof(float));
|
||||
for (int ii = 0; ii < verticesCount; ii++) cmd->colors[ii] = color;
|
||||
memcpy(cmd->indices, indices->buffer(), indices->size() * sizeof(uint16_t));
|
||||
|
||||
if (!lastCommand) {
|
||||
drawable->renderCommand = lastCommand = cmd;
|
||||
} else {
|
||||
lastCommand->next = cmd;
|
||||
lastCommand = cmd;
|
||||
}
|
||||
|
||||
clipper.clipEnd(slot);
|
||||
}
|
||||
clipper.clipEnd();
|
||||
|
||||
return drawable->renderCommand;
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT void spine_skeleton_drawable_dispose(spine_skeleton_drawable *drawable) {
|
||||
if (!drawable) return;
|
||||
if (drawable->skeleton) delete (Skeleton*)drawable->skeleton;
|
||||
if (drawable->animationState) delete (AnimationState*)drawable->animationState;
|
||||
while (drawable->renderCommand) {
|
||||
spine_render_command *cmd = drawable->renderCommand;
|
||||
drawable->renderCommand = cmd->next;
|
||||
spine_render_command_dispose(cmd);
|
||||
}
|
||||
SpineExtension::free(drawable, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
spine::SpineExtension *spine::getDefaultExtension() {
|
||||
return new spine::DefaultSpineExtension();
|
||||
}
|
||||
|
||||
@ -45,3 +45,33 @@ FFI_PLUGIN_EXPORT spine_skeleton_data* spine_skeleton_data_load_json(spine_atlas
|
||||
FFI_PLUGIN_EXPORT spine_skeleton_data* spine_skeleton_data_load_binary(spine_atlas *atlas, const unsigned char *skeletonData, int32_t length);
|
||||
FFI_PLUGIN_EXPORT void spine_skeleton_data_dispose(spine_skeleton_data *skeletonData);
|
||||
|
||||
typedef enum spine_blend_mode {
|
||||
SPINE_BLEND_MODE_NORMAL = 0,
|
||||
SPINE_BLEND_MODE_ADDITIVE,
|
||||
SPINE_BLEND_MODE_MULTIPLY,
|
||||
SPINE_BLEND_MODE_SCREEN
|
||||
} spine_blend_mode;
|
||||
|
||||
typedef struct spine_render_command {
|
||||
float *positions;
|
||||
float *uvs;
|
||||
int32_t *colors;
|
||||
int32_t numVertices;
|
||||
uint16_t *indices;
|
||||
int32_t numIndices;
|
||||
int32_t atlasPage;
|
||||
spine_blend_mode blendMode;
|
||||
struct spine_render_command *next;
|
||||
} spine_render_command;
|
||||
|
||||
typedef struct spine_skeleton_drawable {
|
||||
void *skeleton;
|
||||
void *animationState;
|
||||
spine_render_command *renderCommand;
|
||||
} spine_skeleton_drawable;
|
||||
|
||||
FFI_PLUGIN_EXPORT spine_skeleton_drawable *spine_skeleton_drawable_create(spine_skeleton_data *skeletonData);
|
||||
FFI_PLUGIN_EXPORT void spine_skeleton_drawable_update(spine_skeleton_drawable *drawable, float deltaTime);
|
||||
FFI_PLUGIN_EXPORT spine_render_command *spine_skeleton_drawable_render(spine_skeleton_drawable *drawable);
|
||||
FFI_PLUGIN_EXPORT void spine_skeleton_drawable_dispose(spine_skeleton_drawable *drawable);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user