导出数据转spine

This commit is contained in:
tianmo
2026-09-07 21:29:15 +08:00
parent d258d4f435
commit 3a7c0b4092
65 changed files with 6000 additions and 0 deletions
@@ -0,0 +1,213 @@
#include "RuntimeApi.h"
#include <spine/Animation.h>
#include <spine/AnimationState.h>
#include <spine/AnimationStateData.h>
#include <spine/Atlas.h>
#include <spine/Extension.h>
#include <spine/Skeleton.h>
#include <spine/SkeletonBinary.h>
#include <spine/SkeletonData.h>
#include <spine/SkeletonJson.h>
#include <spine/SkeletonRenderer.h>
#include <spine/Skin.h>
#include <spine/TextureLoader.h>
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
namespace {
struct TextureRecord { std::string path; };
class MetadataTextureLoader final : public spine::TextureLoader {
public:
void load(spine::AtlasPage& page, const spine::String& path) override {
page.texture = new TextureRecord{path.buffer()};
}
void unload(void* texture) override { delete static_cast<TextureRecord*>(texture); }
};
struct RenderBatch {
std::vector<DtsRenderVertex> vertices;
std::vector<std::uint16_t> indices;
std::string texturePath;
std::uint32_t blendMode = 0;
};
struct RuntimeContext {
MetadataTextureLoader textureLoader;
std::unique_ptr<spine::Atlas> atlas;
std::unique_ptr<spine::SkeletonData> skeletonData;
std::unique_ptr<spine::Skeleton> skeleton;
std::unique_ptr<spine::AnimationStateData> animationStateData;
std::unique_ptr<spine::AnimationState> animationState;
std::unique_ptr<spine::SkeletonRenderer> renderer;
std::vector<std::string> animationNames;
std::vector<float> animationDurations;
std::vector<std::string> skinNames;
std::vector<RenderBatch> renderBatches;
std::string error;
};
RuntimeContext* context(DtsRuntimeHandle handle) { return static_cast<RuntimeContext*>(handle); }
std::string lowercaseExtension(const std::string& path) {
const auto dot = path.find_last_of('.');
auto extension = dot == std::string::npos ? std::string{} : path.substr(dot);
std::transform(extension.begin(), extension.end(), extension.begin(),
[](unsigned char value) { return static_cast<char>(std::tolower(value)); });
return extension;
}
void collectMetadata(RuntimeContext& value) {
value.animationNames.clear();
value.animationDurations.clear();
auto& animations = value.skeletonData->getAnimations();
for (std::size_t index = 0; index < animations.size(); ++index) {
value.animationNames.emplace_back(animations[index]->getName().buffer());
value.animationDurations.push_back(animations[index]->getDuration());
}
value.skinNames.clear();
auto& skins = value.skeletonData->getSkins();
for (std::size_t index = 0; index < skins.size(); ++index)
value.skinNames.emplace_back(skins[index]->getName().buffer());
}
void collectDrawCommands(RuntimeContext& value) {
value.renderBatches.clear();
for (auto* command = value.renderer->render(*value.skeleton); command; command = command->next) {
RenderBatch batch;
batch.blendMode = static_cast<std::uint32_t>(command->blendMode);
if (const auto* texture = static_cast<TextureRecord*>(command->texture))
batch.texturePath = texture->path;
for (int index = 0; index < command->numVertices; ++index)
batch.vertices.push_back({command->positions[index * 2], -command->positions[index * 2 + 1],
command->uvs[index * 2], command->uvs[index * 2 + 1], command->colors[index]});
batch.indices.assign(command->indices, command->indices + command->numIndices);
value.renderBatches.push_back(std::move(batch));
}
}
} // namespace
namespace spine {
SpineExtension* getDefaultExtension() { return new DefaultSpineExtension(); }
} // namespace spine
extern "C" {
uint32_t dtsRuntimeGetApiVersion() { return DTS_RUNTIME_API_VERSION; }
int32_t dtsRuntimeGetInfo(DtsRuntimeInfo* info) {
if (!info || info->structSize < sizeof(DtsRuntimeInfo)) return -1;
info->apiVersion = DTS_RUNTIME_API_VERSION;
info->spineVersionLine = "4.2";
info->adapterBuild = "preview-1";
info->capabilities = DTS_RUNTIME_CAP_SKELETON_METADATA | DTS_RUNTIME_CAP_DRAW_COMMANDS;
return 0;
}
DtsRuntimeHandle dtsRuntimeCreate() { return new RuntimeContext; }
void dtsRuntimeDestroy(DtsRuntimeHandle handle) { delete context(handle); }
int32_t dtsRuntimeLoad(DtsRuntimeHandle handle, const DtsLoadRequest* request) {
auto* value = context(handle);
if (!value || !request || request->structSize < sizeof(DtsLoadRequest)
|| !request->skeletonPathUtf8 || !request->atlasPathUtf8) return -1;
value->error.clear();
value->renderBatches.clear();
value->renderer.reset();
value->animationState.reset();
value->animationStateData.reset();
value->skeleton.reset();
value->skeletonData.reset();
value->atlas.reset();
value->atlas = std::make_unique<spine::Atlas>(request->atlasPathUtf8, &value->textureLoader, true);
const float scale = request->scale > 0 ? request->scale : 1.0F;
if (lowercaseExtension(request->skeletonPathUtf8) == ".json") {
spine::SkeletonJson loader(value->atlas.get());
loader.setScale(scale);
value->skeletonData.reset(loader.readSkeletonDataFile(request->skeletonPathUtf8));
if (!value->skeletonData) value->error = loader.getError().buffer();
} else {
spine::SkeletonBinary loader(value->atlas.get());
loader.setScale(scale);
value->skeletonData.reset(loader.readSkeletonDataFile(request->skeletonPathUtf8));
if (!value->skeletonData) value->error = loader.getError().buffer();
}
if (!value->skeletonData) {
if (value->error.empty()) value->error = "Spine Runtime could not load skeleton data.";
return -2;
}
collectMetadata(*value);
value->skeleton = std::make_unique<spine::Skeleton>(value->skeletonData.get());
value->animationStateData = std::make_unique<spine::AnimationStateData>(value->skeletonData.get());
value->animationState = std::make_unique<spine::AnimationState>(value->animationStateData.get());
value->renderer = std::make_unique<spine::SkeletonRenderer>();
if (!value->animationNames.empty())
value->animationState->setAnimation(0, value->animationNames.front().c_str(), true);
value->animationState->apply(*value->skeleton);
value->skeleton->updateWorldTransform(spine::Physics_Update);
collectDrawCommands(*value);
return 0;
}
int32_t dtsRuntimeGetSkeletonInfo(DtsRuntimeHandle handle, DtsSkeletonInfo* info) {
auto* value = context(handle);
if (!value || !value->skeletonData || !info || info->structSize < sizeof(DtsSkeletonInfo)) return -1;
auto* data = value->skeletonData.get();
info->boneCount = static_cast<uint32_t>(data->getBones().size());
info->slotCount = static_cast<uint32_t>(data->getSlots().size());
info->skinCount = static_cast<uint32_t>(value->skinNames.size());
info->animationCount = static_cast<uint32_t>(value->animationNames.size());
info->eventCount = static_cast<uint32_t>(data->getEvents().size());
info->constraintCount = static_cast<uint32_t>(data->getIkConstraints().size()
+ data->getTransformConstraints().size() + data->getPathConstraints().size()
+ data->getPhysicsConstraints().size());
return 0;
}
const char* dtsRuntimeGetAnimationName(DtsRuntimeHandle handle, uint32_t index) {
auto* value = context(handle);
return value && index < value->animationNames.size() ? value->animationNames[index].c_str() : nullptr;
}
float dtsRuntimeGetAnimationDuration(DtsRuntimeHandle handle, uint32_t index) {
auto* value = context(handle);
return value && index < value->animationDurations.size() ? value->animationDurations[index] : 0.0F;
}
const char* dtsRuntimeGetSkinName(DtsRuntimeHandle handle, uint32_t index) {
auto* value = context(handle);
return value && index < value->skinNames.size() ? value->skinNames[index].c_str() : nullptr;
}
const char* dtsRuntimeGetLastError(DtsRuntimeHandle handle) {
auto* value = context(handle);
return value ? value->error.c_str() : "Invalid runtime handle.";
}
int32_t dtsRuntimeSetAnimation(DtsRuntimeHandle handle, const char* name, int32_t loop) {
auto* value = context(handle);
if (!value || !value->animationState || !name) return -1;
if (!value->skeletonData->findAnimation(name)) {
value->error = "Animation was not found.";
return -2;
}
value->skeleton->setToSetupPose();
value->animationState->setAnimation(0, name, loop != 0);
return 0;
}
int32_t dtsRuntimeUpdate(DtsRuntimeHandle handle, float seconds) {
auto* value = context(handle);
if (!value || !value->animationState || !value->skeleton || !value->renderer) return -1;
value->animationState->update(std::max(0.0F, seconds));
value->animationState->apply(*value->skeleton);
value->skeleton->updateWorldTransform(spine::Physics_Update);
collectDrawCommands(*value);
return 0;
}
uint32_t dtsRuntimeGetDrawCommandCount(DtsRuntimeHandle handle) {
auto* value = context(handle);
return value ? static_cast<uint32_t>(value->renderBatches.size()) : 0;
}
int32_t dtsRuntimeGetDrawCommand(DtsRuntimeHandle handle, uint32_t index, DtsDrawCommand* command) {
auto* value = context(handle);
if (!value || index >= value->renderBatches.size() || !command
|| command->structSize < sizeof(DtsDrawCommand)) return -1;
const auto& batch = value->renderBatches[index];
command->vertices = batch.vertices.data();
command->vertexCount = static_cast<uint32_t>(batch.vertices.size());
command->indices = batch.indices.data();
command->indexCount = static_cast<uint32_t>(batch.indices.size());
command->texturePathUtf8 = batch.texturePath.c_str();
command->blendMode = batch.blendMode;
return 0;
}
} // extern "C"