mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
[flutter] skeleton drawable, vertices creation
This commit is contained in:
parent
c1d9a9e23e
commit
887d77ef63
@ -84,11 +84,12 @@ namespace spine {
|
|||||||
TextureWrap vWrap;
|
TextureWrap vWrap;
|
||||||
int width, height;
|
int width, height;
|
||||||
bool pma;
|
bool pma;
|
||||||
|
int index;
|
||||||
|
|
||||||
explicit AtlasPage(const String &inName) : name(inName), format(Format_RGBA8888),
|
explicit AtlasPage(const String &inName) : name(inName), format(Format_RGBA8888),
|
||||||
minFilter(TextureFilter_Nearest),
|
minFilter(TextureFilter_Nearest),
|
||||||
magFilter(TextureFilter_Nearest), uWrap(TextureWrap_ClampToEdge),
|
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 {
|
} else {
|
||||||
page->texturePath = String(path, true);
|
page->texturePath = String(path, true);
|
||||||
}
|
}
|
||||||
|
page->index = _pages.size();
|
||||||
_pages.add(page);
|
_pages.add(page);
|
||||||
} else {
|
} else {
|
||||||
AtlasRegion *region = new (__FILE__, __LINE__) AtlasRegion();
|
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 {
|
void loadSkeleton() async {
|
||||||
final atlas = await spine_flutter.loadAtlas(rootBundle, "assets/spineboy.atlas");
|
final atlas = await spine_flutter.loadAtlas(rootBundle, "assets/skeleton.atlas");
|
||||||
final skeletonData = spine_flutter.loadSkeletonDataJson(atlas, await rootBundle.loadString("assets/spineboy-pro.json"));
|
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 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
|
@override
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -60,6 +62,46 @@ Pointer<spine_skeleton_data> loadSkeletonDataBinary(Pointer<spine_atlas> atlas,
|
|||||||
return skeletonData;
|
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';
|
const String _libName = 'spine_flutter';
|
||||||
|
|
||||||
final DynamicLibrary _dylib = () {
|
final DynamicLibrary _dylib = () {
|
||||||
|
|||||||
@ -129,6 +129,76 @@ class SpineFlutterBindings {
|
|||||||
'spine_skeleton_data_dispose');
|
'spine_skeleton_data_dispose');
|
||||||
late final _spine_skeleton_data_dispose = _spine_skeleton_data_disposePtr
|
late final _spine_skeleton_data_dispose = _spine_skeleton_data_disposePtr
|
||||||
.asFunction<void Function(ffi.Pointer<spine_skeleton_data>)>();
|
.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 {
|
class spine_atlas extends ffi.Struct {
|
||||||
@ -147,3 +217,42 @@ class spine_skeleton_data extends ffi.Struct {
|
|||||||
|
|
||||||
external ffi.Pointer<ffi.Int8> error;
|
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) {
|
FFI_PLUGIN_EXPORT spine_atlas* spine_atlas_load(const char *atlasData) {
|
||||||
|
if (!atlasData) return nullptr;
|
||||||
int length = strlen(atlasData);
|
int length = strlen(atlasData);
|
||||||
auto atlas = new Atlas(atlasData, length, "", (TextureLoader*)nullptr, false);
|
auto atlas = new Atlas(atlasData, length, "", (TextureLoader*)nullptr, false);
|
||||||
spine_atlas *result = SpineExtension::calloc<spine_atlas>(1, __FILE__, __LINE__);
|
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) {
|
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);
|
SkeletonJson json((Atlas*)atlas->atlas);
|
||||||
SkeletonData *data = json.readSkeletonData(skeletonData);
|
SkeletonData *data = json.readSkeletonData(skeletonData);
|
||||||
spine_skeleton_data *result = SpineExtension::calloc<spine_skeleton_data>(1, __FILE__, __LINE__);
|
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) {
|
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);
|
SkeletonBinary binary((Atlas*)atlas->atlas);
|
||||||
SkeletonData *data = binary.readSkeletonData(skeletonData, length);
|
SkeletonData *data = binary.readSkeletonData(skeletonData, length);
|
||||||
spine_skeleton_data *result = SpineExtension::calloc<spine_skeleton_data>(1, __FILE__, __LINE__);
|
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__);
|
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() {
|
spine::SpineExtension *spine::getDefaultExtension() {
|
||||||
return new spine::DefaultSpineExtension();
|
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 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);
|
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