mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
[flutter] Batching of render commands.
This commit is contained in:
parent
bd7ec75749
commit
4e8ca9c46f
@ -116,7 +116,7 @@ class PreloadAndShareSpineDataExample extends FlameGame {
|
||||
// gets their own SkeletonDrawable copy derived from the cached data. The
|
||||
// SkeletonDrawable copies do not own the underlying skeleton data and atlas.
|
||||
final rng = Random();
|
||||
for (int i = 0; i < 50; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final drawable = SkeletonDrawable(cachedAtlas, cachedSkeletonData, false);
|
||||
final scale = 0.1 + rng.nextDouble() * 0.2;
|
||||
final position = Vector2(rng.nextDouble() * size.x, rng.nextDouble() * size.y);
|
||||
|
||||
Binary file not shown.
@ -3342,8 +3342,8 @@ class RenderCommand {
|
||||
// https://github.com/flutter/engine/blob/5c60785b802ad2c8b8899608d949342d5c624952/lib/ui/painting/vertices.cc#L21
|
||||
vertices = Vertices.raw(VertexMode.triangles, positions,
|
||||
textureCoordinates: uvs,
|
||||
colors: _bindings.spine_render_command_get_colors(nativeCmd).asTypedList(numVertices),
|
||||
indices: _bindings.spine_render_command_get_indices(nativeCmd).asTypedList(numIndices));
|
||||
colors: colors,
|
||||
indices: indices);
|
||||
} else {
|
||||
// On the web, rendering is done through CanvasKit, which requires copies of the native data.
|
||||
final positionsCopy = Float32List.fromList(positions);
|
||||
|
||||
@ -49,7 +49,6 @@ struct Block {
|
||||
|
||||
uint8_t* allocate(int numBytes) {
|
||||
uint8_t *ptr = memory + allocated;
|
||||
memset(ptr, 0, numBytes);
|
||||
allocated += numBytes;
|
||||
return ptr;
|
||||
}
|
||||
@ -150,14 +149,25 @@ typedef struct _spine_vector {
|
||||
float x, y;
|
||||
} _spine_vector;
|
||||
|
||||
typedef struct _spine_skeleton_drawable {
|
||||
typedef struct _spine_skeleton_drawable : public SpineObject {
|
||||
spine_skeleton skeleton;
|
||||
spine_animation_state animationState;
|
||||
spine_animation_state_data animationStateData;
|
||||
spine_animation_state_events animationStateEvents;
|
||||
void *clipping;
|
||||
_spine_render_command *renderCommand;
|
||||
BlockAllocator *allocator;
|
||||
Vector<float> worldVertices;
|
||||
Vector<unsigned short> quadIndices;
|
||||
Vector<_spine_render_command *> renderCommands;
|
||||
|
||||
_spine_skeleton_drawable() {
|
||||
quadIndices.add(0);
|
||||
quadIndices.add(1);
|
||||
quadIndices.add(2);
|
||||
quadIndices.add(2);
|
||||
quadIndices.add(3);
|
||||
quadIndices.add(0);
|
||||
}
|
||||
} _spine_skeleton_drawable;
|
||||
|
||||
typedef struct _spine_skin_entry {
|
||||
@ -619,7 +629,7 @@ static _spine_render_command *spine_render_command_create(BlockAllocator &alloca
|
||||
// SkeletonDrawable
|
||||
|
||||
spine_skeleton_drawable spine_skeleton_drawable_create(spine_skeleton_data skeletonData) {
|
||||
_spine_skeleton_drawable *drawable = SpineExtension::calloc<_spine_skeleton_drawable>(1, __FILE__, __LINE__);
|
||||
_spine_skeleton_drawable *drawable = new (__FILE__, __LINE__) _spine_skeleton_drawable();
|
||||
drawable->skeleton = (spine_skeleton) new (__FILE__, __LINE__) Skeleton((SkeletonData *) skeletonData);
|
||||
AnimationStateData *stateData = new (__FILE__, __LINE__) AnimationStateData((SkeletonData *) skeletonData);
|
||||
drawable->animationStateData = (spine_animation_state_data) stateData;
|
||||
@ -646,25 +656,76 @@ void spine_skeleton_drawable_dispose(spine_skeleton_drawable drawable) {
|
||||
SpineExtension::free(drawable, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
static _spine_render_command *batch_sub_commands(BlockAllocator &allocator, Vector<_spine_render_command*> &commands, int first, int last, int numVertices, int numIndices) {
|
||||
_spine_render_command *batched = spine_render_command_create(allocator, numVertices, numIndices, commands[0]->blendMode, commands[0]->atlasPage);
|
||||
float *positions = batched->positions;
|
||||
float *uvs = batched->uvs;
|
||||
int32_t *colors = batched->colors;
|
||||
uint16_t *indices = batched->indices;
|
||||
int indicesOffset = 0;
|
||||
for (int i = first; i <= last; i++) {
|
||||
_spine_render_command *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);
|
||||
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;
|
||||
indices += cmd->numIndices;
|
||||
}
|
||||
return batched;
|
||||
}
|
||||
|
||||
static _spine_render_command *batch_commands(BlockAllocator &allocator, Vector<_spine_render_command*> &commands) {
|
||||
if (commands.size() == 0) return nullptr;
|
||||
|
||||
_spine_render_command *root = nullptr;
|
||||
_spine_render_command *last = nullptr;
|
||||
|
||||
_spine_render_command *first = commands[0];
|
||||
int startIndex = 0;
|
||||
int i = 1;
|
||||
int numVertices = first->numVertices;
|
||||
int numIndices = first->numIndices;
|
||||
while (i <= commands.size()) {
|
||||
_spine_render_command *cmd = i < commands.size() ? commands[i] : nullptr;
|
||||
if (cmd != nullptr && cmd->atlasPage == first->atlasPage &&
|
||||
cmd->blendMode == first->blendMode &&
|
||||
numIndices + cmd->numIndices < 0xffff) {
|
||||
numVertices += cmd->numVertices;
|
||||
numIndices += cmd->numIndices;
|
||||
} else {
|
||||
_spine_render_command *batched = batch_sub_commands(allocator, commands, startIndex, i - 1, numVertices, numIndices);
|
||||
if (!last) {
|
||||
root = last = batched;
|
||||
} else {
|
||||
last->next = batched;
|
||||
last = batched;
|
||||
}
|
||||
if (i == commands.size()) break;
|
||||
first = commands[i];
|
||||
startIndex = i;
|
||||
numVertices = first->numVertices;
|
||||
numIndices = first->numIndices;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable drawable) {
|
||||
_spine_skeleton_drawable *_drawable = (_spine_skeleton_drawable *) drawable;
|
||||
if (!_drawable) return nullptr;
|
||||
if (!_drawable->skeleton) return nullptr;
|
||||
|
||||
_drawable->allocator->compress();
|
||||
_drawable->renderCommand = nullptr;
|
||||
_drawable->renderCommands.clear();
|
||||
|
||||
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 = *(SkeletonClipping *) _drawable->clipping;
|
||||
Skeleton *skeleton = (Skeleton *) _drawable->skeleton;
|
||||
_spine_render_command *lastCommand = nullptr;
|
||||
|
||||
for (unsigned i = 0; i < skeleton->getSlots().size(); ++i) {
|
||||
Slot &slot = *skeleton->getDrawOrder()[i];
|
||||
@ -677,7 +738,9 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<float> *vertices = &worldVertices;
|
||||
Vector<float> *worldVertices = &_drawable->worldVertices;
|
||||
Vector<unsigned short> *quadIndices = &_drawable->quadIndices;
|
||||
Vector<float> *vertices = worldVertices;
|
||||
int32_t verticesCount;
|
||||
Vector<float> *uvs;
|
||||
Vector<unsigned short> *indices;
|
||||
@ -695,11 +758,11 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
|
||||
continue;
|
||||
}
|
||||
|
||||
worldVertices.setSize(8, 0);
|
||||
regionAttachment->computeWorldVertices(slot, worldVertices, 0, 2);
|
||||
worldVertices->setSize(8, 0);
|
||||
regionAttachment->computeWorldVertices(slot, *worldVertices, 0, 2);
|
||||
verticesCount = 4;
|
||||
uvs = ®ionAttachment->getUVs();
|
||||
indices = &quadIndices;
|
||||
indices = quadIndices;
|
||||
indicesCount = 6;
|
||||
pageIndex = ((AtlasRegion *) regionAttachment->getRegion())->page->index;
|
||||
|
||||
@ -713,8 +776,8 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
|
||||
continue;
|
||||
}
|
||||
|
||||
worldVertices.setSize(mesh->getWorldVerticesLength(), 0);
|
||||
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices.buffer(), 0, 2);
|
||||
worldVertices->setSize(mesh->getWorldVerticesLength(), 0);
|
||||
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices->buffer(), 0, 2);
|
||||
verticesCount = (int32_t) (mesh->getWorldVerticesLength() >> 1);
|
||||
uvs = &mesh->getUVs();
|
||||
indices = &mesh->getTriangles();
|
||||
@ -735,7 +798,7 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
|
||||
uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTriangles(worldVertices, *indices, *uvs, 2);
|
||||
clipper.clipTriangles(*worldVertices, *indices, *uvs, 2);
|
||||
vertices = &clipper.getClippedVertices();
|
||||
verticesCount = (int32_t) (clipper.getClippedVertices().size() >> 1);
|
||||
uvs = &clipper.getClippedUVs();
|
||||
@ -744,24 +807,16 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
|
||||
}
|
||||
|
||||
_spine_render_command *cmd = spine_render_command_create(*_drawable->allocator, verticesCount, indicesCount, (spine_blend_mode) slot.getData().getBlendMode(), pageIndex);
|
||||
|
||||
_drawable->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;
|
||||
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 (spine_render_command) _drawable->renderCommand;
|
||||
return (spine_render_command) batch_commands(*_drawable->allocator, _drawable->renderCommands);
|
||||
}
|
||||
|
||||
spine_skeleton spine_skeleton_drawable_get_skeleton(spine_skeleton_drawable drawable) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user