Formatting

This commit is contained in:
Mario Zechner 2026-03-14 15:39:56 +01:00
parent 9ec6ead094
commit e5bc9b709e
13 changed files with 584 additions and 581 deletions

View File

@ -140,7 +140,8 @@ public class SkeletonRenderer {
} }
command.vertices.setSize(command.vertices.size + verticesLength); command.vertices.setSize(command.vertices.size + verticesLength);
region.computeWorldVertices(slot, sequence.getOffsets(sequenceIndex), command.vertices.items, vertexStart, vertexSize); region.computeWorldVertices(slot, sequence.getOffsets(sequenceIndex), command.vertices.items, vertexStart,
vertexSize);
uvs = sequence.getUVs(sequenceIndex); uvs = sequence.getUVs(sequenceIndex);
indices = quadTriangles; indices = quadTriangles;
color = region.getColor(); color = region.getColor();

View File

@ -5,6 +5,5 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
} }

View File

@ -65,53 +65,53 @@ int main() {
{ {
int atlas_length = 0; int atlas_length = 0;
uint8_t *atlas_bytes = read_file("data/dragon-pma.atlas", &atlas_length); uint8_t *atlas_bytes = read_file("data/dragon-pma.atlas", &atlas_length);
spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture); spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture);
spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result); spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result);
spine_atlas_result_dispose(atlas_result); spine_atlas_result_dispose(atlas_result);
int skeleton_length = 0; int skeleton_length = 0;
uint8_t *skeleton_bytes = read_file("data/dragon-ess.skel", &skeleton_length); uint8_t *skeleton_bytes = read_file("data/dragon-ess.skel", &skeleton_length);
spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length, "data/dragon-ess.skel"); spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length, "data/dragon-ess.skel");
spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result); spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result);
spine_skeleton_data_result_dispose(skeleton_result); spine_skeleton_data_result_dispose(skeleton_result);
spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data); spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data);
spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable); spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable);
spine_skeleton_set_position(skeleton, width / 2.0f, height / 2.0f); spine_skeleton_set_position(skeleton, width / 2.0f, height / 2.0f);
spine_skeleton_set_scale(skeleton, 0.5f, 0.5f); spine_skeleton_set_scale(skeleton, 0.5f, 0.5f);
spine_skeleton_setup_pose(skeleton); spine_skeleton_setup_pose(skeleton);
spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable); spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable);
spine_animation_state_set_animation_1(animation_state, 0, "flying", true); spine_animation_state_set_animation_1(animation_state, 0, "flying", true);
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = (float) (currTime - lastTime); float delta = (float) (currTime - lastTime);
lastTime = currTime; lastTime = currTime;
spine_animation_state_update(animation_state, delta); spine_animation_state_update(animation_state, delta);
spine_animation_state_apply(animation_state, skeleton); spine_animation_state_apply(animation_state, skeleton);
spine_skeleton_update(skeleton, delta); spine_skeleton_update(skeleton, delta);
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE); spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
gl::glClear(gl::GL_COLOR_BUFFER_BIT); gl::glClear(gl::GL_COLOR_BUFFER_BIT);
renderer_draw_c(renderer, skeleton, true); renderer_draw_c(renderer, skeleton, true);
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
} }
renderer_dispose(renderer); renderer_dispose(renderer);
spine_skeleton_drawable_dispose(drawable); spine_skeleton_drawable_dispose(drawable);
spine_skeleton_data_dispose(skeleton_data); spine_skeleton_data_dispose(skeleton_data);
spine_atlas_dispose(atlas); spine_atlas_dispose(atlas);
free(atlas_bytes); free(atlas_bytes);
free(skeleton_bytes); free(skeleton_bytes);
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -65,53 +65,53 @@ int main() {
{ {
int atlas_length = 0; int atlas_length = 0;
uint8_t *atlas_bytes = read_file("data/dragon-pma.atlas", &atlas_length); uint8_t *atlas_bytes = read_file("data/dragon-pma.atlas", &atlas_length);
spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture); spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture);
spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result); spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result);
spine_atlas_result_dispose(atlas_result); spine_atlas_result_dispose(atlas_result);
int skeleton_length = 0; int skeleton_length = 0;
uint8_t *skeleton_bytes = read_file("data/dragon-ess.json", &skeleton_length); uint8_t *skeleton_bytes = read_file("data/dragon-ess.json", &skeleton_length);
spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_json(atlas, (const char *) skeleton_bytes, "data/dragon-ess.json"); spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_json(atlas, (const char *) skeleton_bytes, "data/dragon-ess.json");
spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result); spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result);
spine_skeleton_data_result_dispose(skeleton_result); spine_skeleton_data_result_dispose(skeleton_result);
spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data); spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data);
spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable); spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable);
spine_skeleton_set_position(skeleton, width / 2.0f, height / 2.0f); spine_skeleton_set_position(skeleton, width / 2.0f, height / 2.0f);
spine_skeleton_set_scale(skeleton, 0.5f, 0.5f); spine_skeleton_set_scale(skeleton, 0.5f, 0.5f);
spine_skeleton_setup_pose(skeleton); spine_skeleton_setup_pose(skeleton);
spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable); spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable);
spine_animation_state_set_animation_1(animation_state, 0, "flying", true); spine_animation_state_set_animation_1(animation_state, 0, "flying", true);
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = (float) (currTime - lastTime); float delta = (float) (currTime - lastTime);
lastTime = currTime; lastTime = currTime;
spine_animation_state_update(animation_state, delta); spine_animation_state_update(animation_state, delta);
spine_animation_state_apply(animation_state, skeleton); spine_animation_state_apply(animation_state, skeleton);
spine_skeleton_update(skeleton, delta); spine_skeleton_update(skeleton, delta);
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE); spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
gl::glClear(gl::GL_COLOR_BUFFER_BIT); gl::glClear(gl::GL_COLOR_BUFFER_BIT);
renderer_draw_c(renderer, skeleton, true); renderer_draw_c(renderer, skeleton, true);
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
} }
renderer_dispose(renderer); renderer_dispose(renderer);
spine_skeleton_drawable_dispose(drawable); spine_skeleton_drawable_dispose(drawable);
spine_skeleton_data_dispose(skeleton_data); spine_skeleton_data_dispose(skeleton_data);
spine_atlas_dispose(atlas); spine_atlas_dispose(atlas);
free(atlas_bytes); free(atlas_bytes);
free(skeleton_bytes); free(skeleton_bytes);
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -67,50 +67,50 @@ int main() {
{ {
GlTextureLoader textureLoader; GlTextureLoader textureLoader;
Atlas *atlas = new Atlas("data/dragon-pma.atlas", &textureLoader); Atlas *atlas = new Atlas("data/dragon-pma.atlas", &textureLoader);
SkeletonJson json(*atlas); SkeletonJson json(*atlas);
SkeletonData *skeletonData = json.readSkeletonDataFile("data/dragon-ess.json"); SkeletonData *skeletonData = json.readSkeletonDataFile("data/dragon-ess.json");
if (!skeletonData) { if (!skeletonData) {
std::cerr << "Failed to load dragon: " << json.getError().buffer() << std::endl; std::cerr << "Failed to load dragon: " << json.getError().buffer() << std::endl;
return -1; return -1;
} }
Skeleton skeleton(*skeletonData); Skeleton skeleton(*skeletonData);
skeleton.setPosition(width / 2, height / 2); skeleton.setPosition(width / 2, height / 2);
skeleton.setScaleX(0.5f); skeleton.setScaleX(0.5f);
skeleton.setScaleY(0.5f); skeleton.setScaleY(0.5f);
skeleton.setupPose(); skeleton.setupPose();
AnimationStateData animationStateData(*skeletonData); AnimationStateData animationStateData(*skeletonData);
AnimationState animationState(animationStateData); AnimationState animationState(animationStateData);
animationState.setAnimation(0, "flying", true); animationState.setAnimation(0, "flying", true);
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = currTime - lastTime; float delta = currTime - lastTime;
lastTime = currTime; lastTime = currTime;
animationState.update(delta); animationState.update(delta);
animationState.apply(skeleton); animationState.apply(skeleton);
skeleton.update(delta); skeleton.update(delta);
skeleton.updateWorldTransform(spine::Physics_Update); skeleton.updateWorldTransform(spine::Physics_Update);
gl::glClear(gl::GL_COLOR_BUFFER_BIT); gl::glClear(gl::GL_COLOR_BUFFER_BIT);
renderer_draw(renderer, &skeleton, true); renderer_draw(renderer, &skeleton, true);
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
} }
renderer_dispose(renderer); renderer_dispose(renderer);
delete skeletonData; delete skeletonData;
delete atlas; delete atlas;
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -67,50 +67,50 @@ int main() {
{ {
GlTextureLoader textureLoader; GlTextureLoader textureLoader;
Atlas *atlas = new Atlas("data/dragon-pma.atlas", &textureLoader); Atlas *atlas = new Atlas("data/dragon-pma.atlas", &textureLoader);
SkeletonBinary binary(*atlas); SkeletonBinary binary(*atlas);
SkeletonData *skeletonData = binary.readSkeletonDataFile("data/dragon-ess.skel"); SkeletonData *skeletonData = binary.readSkeletonDataFile("data/dragon-ess.skel");
if (!skeletonData) { if (!skeletonData) {
std::cerr << "Failed to load dragon: " << binary.getError().buffer() << std::endl; std::cerr << "Failed to load dragon: " << binary.getError().buffer() << std::endl;
return -1; return -1;
} }
Skeleton skeleton(*skeletonData); Skeleton skeleton(*skeletonData);
skeleton.setPosition(width / 2, height / 2); skeleton.setPosition(width / 2, height / 2);
skeleton.setScaleX(0.5); skeleton.setScaleX(0.5);
skeleton.setScaleY(0.5); skeleton.setScaleY(0.5);
skeleton.setupPose(); skeleton.setupPose();
AnimationStateData animationStateData(*skeletonData); AnimationStateData animationStateData(*skeletonData);
AnimationState animationState(animationStateData); AnimationState animationState(animationStateData);
animationState.setAnimation(0, "flying", true); animationState.setAnimation(0, "flying", true);
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = currTime - lastTime; float delta = currTime - lastTime;
lastTime = currTime; lastTime = currTime;
animationState.update(delta); animationState.update(delta);
animationState.apply(skeleton); animationState.apply(skeleton);
skeleton.update(delta); skeleton.update(delta);
skeleton.updateWorldTransform(spine::Physics_Update); skeleton.updateWorldTransform(spine::Physics_Update);
gl::glClear(gl::GL_COLOR_BUFFER_BIT); gl::glClear(gl::GL_COLOR_BUFFER_BIT);
renderer_draw(renderer, &skeleton, true); renderer_draw(renderer, &skeleton, true);
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
} }
renderer_dispose(renderer); renderer_dispose(renderer);
delete skeletonData; delete skeletonData;
delete atlas; delete atlas;
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -73,67 +73,68 @@ int main() {
{ {
int atlas_length = 0; int atlas_length = 0;
uint8_t *atlas_bytes = read_file("data/spineboy-pma.atlas", &atlas_length); uint8_t *atlas_bytes = read_file("data/spineboy-pma.atlas", &atlas_length);
spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture); spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture);
spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result); spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result);
spine_atlas_result_dispose(atlas_result); spine_atlas_result_dispose(atlas_result);
int skeleton_length = 0; int skeleton_length = 0;
uint8_t *skeleton_bytes = read_file("data/spineboy-pro.skel", &skeleton_length); uint8_t *skeleton_bytes = read_file("data/spineboy-pro.skel", &skeleton_length);
spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length, "data/spineboy-pro.skel"); spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length,
spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result); "data/spineboy-pro.skel");
spine_skeleton_data_result_dispose(skeleton_result); spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result);
spine_skeleton_data_result_dispose(skeleton_result);
spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data); spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data);
spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable); spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable);
spine_skeleton_set_scale(skeleton, 0.5f, 0.5f); spine_skeleton_set_scale(skeleton, 0.5f, 0.5f);
spine_skeleton_setup_pose(skeleton); spine_skeleton_setup_pose(skeleton);
spine_skeleton_set_position(skeleton, 200.0f, height / 2.0f + 150.0f); spine_skeleton_set_position(skeleton, 200.0f, height / 2.0f + 150.0f);
spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable); spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable);
spine_animation_state_set_animation_1(animation_state, 0, "walk", true); spine_animation_state_set_animation_1(animation_state, 0, "walk", true);
spine_animation_state_set_animation_1(animation_state, 1, "aim", true); spine_animation_state_set_animation_1(animation_state, 1, "aim", true);
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = (float) (currTime - lastTime); float delta = (float) (currTime - lastTime);
lastTime = currTime; lastTime = currTime;
spine_animation_state_update(animation_state, delta); spine_animation_state_update(animation_state, delta);
spine_animation_state_apply(animation_state, skeleton); spine_animation_state_apply(animation_state, skeleton);
spine_skeleton_update(skeleton, delta); spine_skeleton_update(skeleton, delta);
spine_bone crosshair_bone = spine_skeleton_find_bone(skeleton, "crosshair"); spine_bone crosshair_bone = spine_skeleton_find_bone(skeleton, "crosshair");
if (crosshair_bone != nullptr) { if (crosshair_bone != nullptr) {
spine_bone parent = spine_bone_get_parent(crosshair_bone); spine_bone parent = spine_bone_get_parent(crosshair_bone);
if (parent != nullptr) { if (parent != nullptr) {
float localX = 0, localY = 0; float localX = 0, localY = 0;
spine_bone_pose parent_pose = spine_bone_get_applied_pose(parent); spine_bone_pose parent_pose = spine_bone_get_applied_pose(parent);
spine_bone_pose_world_to_local(parent_pose, (float) mouseX, (float) mouseY, &localX, &localY); spine_bone_pose_world_to_local(parent_pose, (float) mouseX, (float) mouseY, &localX, &localY);
spine_bone_pose crosshair_pose = spine_bone_get_applied_pose(crosshair_bone); spine_bone_pose crosshair_pose = spine_bone_get_applied_pose(crosshair_bone);
spine_bone_pose_set_x(crosshair_pose, localX); spine_bone_pose_set_x(crosshair_pose, localX);
spine_bone_pose_set_y(crosshair_pose, localY); spine_bone_pose_set_y(crosshair_pose, localY);
}
} }
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
gl::glClear(gl::GL_COLOR_BUFFER_BIT);
renderer_draw_c(renderer, skeleton, true);
glfwSwapBuffers(window);
glfwPollEvents();
} }
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE); renderer_dispose(renderer);
gl::glClear(gl::GL_COLOR_BUFFER_BIT); spine_skeleton_drawable_dispose(drawable);
renderer_draw_c(renderer, skeleton, true); spine_skeleton_data_dispose(skeleton_data);
glfwSwapBuffers(window); spine_atlas_dispose(atlas);
glfwPollEvents(); free(atlas_bytes);
} free(skeleton_bytes);
renderer_dispose(renderer);
spine_skeleton_drawable_dispose(drawable);
spine_skeleton_data_dispose(skeleton_data);
spine_atlas_dispose(atlas);
free(atlas_bytes);
free(skeleton_bytes);
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -82,93 +82,93 @@ int main() {
{ {
// Load the atlas and the skeleton data // Load the atlas and the skeleton data
GlTextureLoader textureLoader; GlTextureLoader textureLoader;
Atlas *atlas = new Atlas("data/spineboy-pma.atlas", &textureLoader); Atlas *atlas = new Atlas("data/spineboy-pma.atlas", &textureLoader);
SkeletonBinary binary(*atlas); SkeletonBinary binary(*atlas);
SkeletonData *skeletonData = binary.readSkeletonDataFile("data/spineboy-pro.skel"); SkeletonData *skeletonData = binary.readSkeletonDataFile("data/spineboy-pro.skel");
// Create a skeleton from the data // Create a skeleton from the data
Skeleton skeleton(*skeletonData); Skeleton skeleton(*skeletonData);
skeleton.setScaleX(0.5); skeleton.setScaleX(0.5);
skeleton.setScaleY(0.5); skeleton.setScaleY(0.5);
skeleton.setupPose(); skeleton.setupPose();
// Position the skeleton on the left side like in the Flutter example // Position the skeleton on the left side like in the Flutter example
skeleton.setPosition(200, height / 2 + 150); skeleton.setPosition(200, height / 2 + 150);
// Set the global skeleton pointer for IK // Set the global skeleton pointer for IK
ikSkeleton = &skeleton; ikSkeleton = &skeleton;
// Create an AnimationState to drive animations on the skeleton // Create an AnimationState to drive animations on the skeleton
AnimationStateData animationStateData(*skeletonData); AnimationStateData animationStateData(*skeletonData);
AnimationState animationState(animationStateData); AnimationState animationState(animationStateData);
// Set the walk animation on track 0 and aim animation on track 1 // Set the walk animation on track 0 and aim animation on track 1
animationState.setAnimation(0, "walk", true); animationState.setAnimation(0, "walk", true);
animationState.setAnimation(1, "aim", true); animationState.setAnimation(1, "aim", true);
// Create the renderer and set the viewport size to match the window size // Create the renderer and set the viewport size to match the window size
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
// Rendering loop // Rendering loop
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
// Calculate the delta time in seconds // Calculate the delta time in seconds
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = currTime - lastTime; float delta = currTime - lastTime;
lastTime = currTime; lastTime = currTime;
// Update and apply the animation state to the skeleton // Update and apply the animation state to the skeleton
animationState.update(delta); animationState.update(delta);
animationState.apply(skeleton); animationState.apply(skeleton);
// Update the skeleton time (used for physics) // Update the skeleton time (used for physics)
skeleton.update(delta); skeleton.update(delta);
// Update the crosshair bone position based on mouse position // Update the crosshair bone position based on mouse position
Bone *crosshairBone = skeleton.findBone("crosshair"); Bone *crosshairBone = skeleton.findBone("crosshair");
if (crosshairBone != nullptr) { if (crosshairBone != nullptr) {
Bone *parent = crosshairBone->getParent(); Bone *parent = crosshairBone->getParent();
if (parent != nullptr) { if (parent != nullptr) {
// Convert mouse position to world coordinates // Convert mouse position to world coordinates
float worldX = mouseX; float worldX = mouseX;
float worldY = mouseY; float worldY = mouseY;
// Convert world position to parent's local space // Convert world position to parent's local space
float localX, localY; float localX, localY;
parent->getAppliedPose().worldToLocal(worldX, worldY, localX, localY); parent->getAppliedPose().worldToLocal(worldX, worldY, localX, localY);
// Set the crosshair bone position in its applied pose // Set the crosshair bone position in its applied pose
crosshairBone->getAppliedPose().setX(localX); crosshairBone->getAppliedPose().setX(localX);
crosshairBone->getAppliedPose().setY(localY); crosshairBone->getAppliedPose().setY(localY);
}
} }
// Calculate the new pose
skeleton.updateWorldTransform(spine::Physics_Update);
// Clear the screen
gl::glClear(gl::GL_COLOR_BUFFER_BIT);
// Render the skeleton in its current pose
renderer_draw(renderer, &skeleton, true);
// Present the rendering results and poll for events
glfwSwapBuffers(window);
glfwPollEvents();
} }
// Calculate the new pose // Clear the IK skeleton pointer
skeleton.updateWorldTransform(spine::Physics_Update); ikSkeleton = nullptr;
// Clear the screen // Dispose everything
gl::glClear(gl::GL_COLOR_BUFFER_BIT); renderer_dispose(renderer);
delete skeletonData;
delete atlas;
// Render the skeleton in its current pose // Kill the window and GLFW
renderer_draw(renderer, &skeleton, true);
// Present the rendering results and poll for events
glfwSwapBuffers(window);
glfwPollEvents();
}
// Clear the IK skeleton pointer
ikSkeleton = nullptr;
// Dispose everything
renderer_dispose(renderer);
delete skeletonData;
delete atlas;
// Kill the window and GLFW
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -102,80 +102,80 @@ int main() {
{ {
// Load the atlas and the skeleton data // Load the atlas and the skeleton data
int atlas_length = 0; int atlas_length = 0;
uint8_t *atlas_bytes = read_file("data/spineboy-pma.atlas", &atlas_length); uint8_t *atlas_bytes = read_file("data/spineboy-pma.atlas", &atlas_length);
spine_atlas_result result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture); spine_atlas_result result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture);
spine_atlas atlas = spine_atlas_result_get_atlas(result); spine_atlas atlas = spine_atlas_result_get_atlas(result);
spine_atlas_result_dispose(result); spine_atlas_result_dispose(result);
int skeleton_length = 0; int skeleton_length = 0;
// uint8_t *skeleton_bytes = read_file("data/spineboy-pro.skel", &skeleton_length); // uint8_t *skeleton_bytes = read_file("data/spineboy-pro.skel", &skeleton_length);
// spine_skeleton_data_result result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length); // spine_skeleton_data_result result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length);
uint8_t *skeleton_bytes = read_file("data/spineboy-pro.json", &skeleton_length); uint8_t *skeleton_bytes = read_file("data/spineboy-pro.json", &skeleton_length);
spine_skeleton_data_result result2 = spine_skeleton_data_load_json(atlas, (const char *) skeleton_bytes, "data/"); spine_skeleton_data_result result2 = spine_skeleton_data_load_json(atlas, (const char *) skeleton_bytes, "data/");
spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(result2); spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(result2);
spine_skeleton_data_result_dispose(result2); spine_skeleton_data_result_dispose(result2);
// Create a skeleton from the data, set the skeleton's position to the bottom center of // Create a skeleton from the data, set the skeleton's position to the bottom center of
// the screen and scale it to make it smaller. // the screen and scale it to make it smaller.
spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data); spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data);
spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable); spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable);
spine_skeleton_set_position(skeleton, width / 2, height - 100); spine_skeleton_set_position(skeleton, width / 2, height - 100);
spine_skeleton_set_scale(skeleton, 0.3f, 0.3f); spine_skeleton_set_scale(skeleton, 0.3f, 0.3f);
// Create an AnimationState to drive animations on the skeleton. Set the "portal" animation // Create an AnimationState to drive animations on the skeleton. Set the "portal" animation
// on track with index 0. // on track with index 0.
spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable); spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable);
spine_animation_state_data animation_state_data = spine_animation_state_get_data(animation_state); spine_animation_state_data animation_state_data = spine_animation_state_get_data(animation_state);
spine_animation_state_data_set_default_mix(animation_state_data, 0.2f); spine_animation_state_data_set_default_mix(animation_state_data, 0.2f);
spine_animation_state_set_animation_1(animation_state, 0, "portal", true); spine_animation_state_set_animation_1(animation_state, 0, "portal", true);
spine_track_entry entry = spine_animation_state_add_animation_1(animation_state, 0, "run", true, 0); spine_track_entry entry = spine_animation_state_add_animation_1(animation_state, 0, "run", true, 0);
spine_track_entry_set_listener(entry, track_listener, NULL); spine_track_entry_set_listener(entry, track_listener, NULL);
// Create the renderer and set the viewport size to match the window size. This sets up a // Create the renderer and set the viewport size to match the window size. This sets up a
// pixel perfect orthogonal projection for 2D rendering. // pixel perfect orthogonal projection for 2D rendering.
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
// Rendering loop // Rendering loop
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
// Calculate the delta time in seconds // Calculate the delta time in seconds
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = currTime - lastTime; float delta = currTime - lastTime;
lastTime = currTime; lastTime = currTime;
// Update and apply the animation state to the skeleton // Update and apply the animation state to the skeleton
spine_animation_state_update(animation_state, delta); spine_animation_state_update(animation_state, delta);
spine_animation_state_apply(animation_state, skeleton); spine_animation_state_apply(animation_state, skeleton);
// Update the skeleton time (used for physics) // Update the skeleton time (used for physics)
spine_skeleton_update(skeleton, delta); spine_skeleton_update(skeleton, delta);
// Calculate the new pose // Calculate the new pose
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE); spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
// Clear the screen // Clear the screen
gl::glClear(gl::GL_COLOR_BUFFER_BIT); gl::glClear(gl::GL_COLOR_BUFFER_BIT);
// Render the skeleton in its current pose // Render the skeleton in its current pose
renderer_draw_c(renderer, skeleton, true); renderer_draw_c(renderer, skeleton, true);
// Present the rendering results and poll for events // Present the rendering results and poll for events
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
} }
// Dispose everything // Dispose everything
renderer_dispose(renderer); renderer_dispose(renderer);
spine_skeleton_drawable_dispose(drawable); spine_skeleton_drawable_dispose(drawable);
spine_skeleton_data_dispose(skeleton_data); spine_skeleton_data_dispose(skeleton_data);
spine_atlas_dispose(atlas); spine_atlas_dispose(atlas);
free(atlas_bytes); free(atlas_bytes);
free(skeleton_bytes); free(skeleton_bytes);
// Kill the window and GLFW // Kill the window and GLFW
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -82,8 +82,7 @@ int main() {
skeleton.setupPose(); skeleton.setupPose();
skeleton.updateWorldTransform(spine::Physics_None); skeleton.updateWorldTransform(spine::Physics_None);
std::cout << "Loaded mix-and-match successfully. Bones=" << skeletonData->getBones().size() std::cout << "Loaded mix-and-match successfully. Bones=" << skeletonData->getBones().size() << ", slots=" << skeletonData->getSlots().size()
<< ", slots=" << skeletonData->getSlots().size()
<< ", skins=" << skeletonData->getSkins().size() << std::endl; << ", skins=" << skeletonData->getSkins().size() << std::endl;
delete skeletonData; delete skeletonData;

View File

@ -94,57 +94,57 @@ int main() {
{ {
int atlas_length = 0; int atlas_length = 0;
uint8_t *atlas_bytes = read_file("data/celestial-circus-pma.atlas", &atlas_length); uint8_t *atlas_bytes = read_file("data/celestial-circus-pma.atlas", &atlas_length);
spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture); spine_atlas_result atlas_result = spine_atlas_load_callback((const char *) atlas_bytes, "data/", load_texture, unload_texture);
spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result); spine_atlas atlas = spine_atlas_result_get_atlas(atlas_result);
spine_atlas_result_dispose(atlas_result); spine_atlas_result_dispose(atlas_result);
int skeleton_length = 0; int skeleton_length = 0;
uint8_t *skeleton_bytes = read_file("data/celestial-circus-pro.skel", &skeleton_length); uint8_t *skeleton_bytes = read_file("data/celestial-circus-pro.skel", &skeleton_length);
spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length, spine_skeleton_data_result skeleton_result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length,
"data/celestial-circus-pro.skel"); "data/celestial-circus-pro.skel");
spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result); spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(skeleton_result);
spine_skeleton_data_result_dispose(skeleton_result); spine_skeleton_data_result_dispose(skeleton_result);
spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data); spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data);
spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable); spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable);
spine_skeleton_set_scale(skeleton, 0.2f, 0.2f); spine_skeleton_set_scale(skeleton, 0.2f, 0.2f);
spine_skeleton_setup_pose(skeleton); spine_skeleton_setup_pose(skeleton);
spine_skeleton_update(skeleton, 0); spine_skeleton_update(skeleton, 0);
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
spine_skeleton_set_position(skeleton, width / 2.0f, height / 2.0f + 150.0f);
dragSkeleton = skeleton;
spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable);
spine_animation_state_set_animation_1(animation_state, 0, "eyeblink-long", true);
spine_animation_state_set_animation_1(animation_state, 1, "wind-idle", true);
renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height);
double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) {
double currTime = glfwGetTime();
float delta = (float) (currTime - lastTime);
lastTime = currTime;
spine_animation_state_update(animation_state, delta);
spine_animation_state_apply(animation_state, skeleton);
spine_skeleton_update(skeleton, delta);
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE); spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
gl::glClear(gl::GL_COLOR_BUFFER_BIT); spine_skeleton_set_position(skeleton, width / 2.0f, height / 2.0f + 150.0f);
renderer_draw_c(renderer, skeleton, true); dragSkeleton = skeleton;
glfwSwapBuffers(window);
glfwPollEvents();
}
dragSkeleton = nullptr; spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable);
renderer_dispose(renderer); spine_animation_state_set_animation_1(animation_state, 0, "eyeblink-long", true);
spine_skeleton_drawable_dispose(drawable); spine_animation_state_set_animation_1(animation_state, 1, "wind-idle", true);
spine_skeleton_data_dispose(skeleton_data);
spine_atlas_dispose(atlas); renderer_t *renderer = renderer_create();
free(atlas_bytes); renderer_set_viewport_size(renderer, width, height);
free(skeleton_bytes);
double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) {
double currTime = glfwGetTime();
float delta = (float) (currTime - lastTime);
lastTime = currTime;
spine_animation_state_update(animation_state, delta);
spine_animation_state_apply(animation_state, skeleton);
spine_skeleton_update(skeleton, delta);
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
gl::glClear(gl::GL_COLOR_BUFFER_BIT);
renderer_draw_c(renderer, skeleton, true);
glfwSwapBuffers(window);
glfwPollEvents();
}
dragSkeleton = nullptr;
renderer_dispose(renderer);
spine_skeleton_drawable_dispose(drawable);
spine_skeleton_data_dispose(skeleton_data);
spine_atlas_dispose(atlas);
free(atlas_bytes);
free(skeleton_bytes);
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -104,76 +104,76 @@ int main() {
{ {
// Load the atlas and the skeleton data // Load the atlas and the skeleton data
GlTextureLoader textureLoader; GlTextureLoader textureLoader;
Atlas *atlas = new Atlas("data/celestial-circus-pma.atlas", &textureLoader); Atlas *atlas = new Atlas("data/celestial-circus-pma.atlas", &textureLoader);
SkeletonBinary binary(*atlas); SkeletonBinary binary(*atlas);
binary.setScale(0.2f); binary.setScale(0.2f);
SkeletonData *skeletonData = binary.readSkeletonDataFile("data/celestial-circus-pro.skel"); SkeletonData *skeletonData = binary.readSkeletonDataFile("data/celestial-circus-pro.skel");
// Create a skeleton from the data // Create a skeleton from the data
Skeleton skeleton(*skeletonData); Skeleton skeleton(*skeletonData);
skeleton.setupPose(); skeleton.setupPose();
skeleton.update(0); skeleton.update(0);
skeleton.updateWorldTransform(Physics_Update); skeleton.updateWorldTransform(Physics_Update);
// Center the skeleton on screen // Center the skeleton on screen
skeleton.setPosition(width / 2, height / 2 + 150); skeleton.setPosition(width / 2, height / 2 + 150);
// Set the global skeleton pointer for mouse dragging // Set the global skeleton pointer for mouse dragging
dragSkeleton = &skeleton; dragSkeleton = &skeleton;
// Create an AnimationState to drive animations on the skeleton // Create an AnimationState to drive animations on the skeleton
AnimationStateData animationStateData(*skeletonData); AnimationStateData animationStateData(*skeletonData);
AnimationState animationState(animationStateData); AnimationState animationState(animationStateData);
// Set the "eyeblink-long" animation like in the web example // Set the "eyeblink-long" animation like in the web example
animationState.setAnimation(0, "eyeblink-long", true); animationState.setAnimation(0, "eyeblink-long", true);
animationState.setAnimation(1, "wind-idle", true); animationState.setAnimation(1, "wind-idle", true);
// Create the renderer and set the viewport size to match the window size. This sets up a // Create the renderer and set the viewport size to match the window size. This sets up a
// pixel perfect orthogonal projection for 2D rendering. // pixel perfect orthogonal projection for 2D rendering.
renderer_t *renderer = renderer_create(); renderer_t *renderer = renderer_create();
renderer_set_viewport_size(renderer, width, height); renderer_set_viewport_size(renderer, width, height);
// Rendering loop // Rendering loop
double lastTime = glfwGetTime(); double lastTime = glfwGetTime();
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
// Calculate the delta time in seconds // Calculate the delta time in seconds
double currTime = glfwGetTime(); double currTime = glfwGetTime();
float delta = currTime - lastTime; float delta = currTime - lastTime;
lastTime = currTime; lastTime = currTime;
// Update and apply the animation state to the skeleton // Update and apply the animation state to the skeleton
animationState.update(delta); animationState.update(delta);
animationState.apply(skeleton); animationState.apply(skeleton);
// Update the skeleton time (used for physics) // Update the skeleton time (used for physics)
skeleton.update(delta); skeleton.update(delta);
// Calculate the new pose // Calculate the new pose
skeleton.updateWorldTransform(spine::Physics_Update); skeleton.updateWorldTransform(spine::Physics_Update);
// Clear the screen // Clear the screen
gl::glClear(gl::GL_COLOR_BUFFER_BIT); gl::glClear(gl::GL_COLOR_BUFFER_BIT);
// Render the skeleton in its current pose // Render the skeleton in its current pose
renderer_draw(renderer, &skeleton, true); renderer_draw(renderer, &skeleton, true);
// Present the rendering results and poll for events // Present the rendering results and poll for events
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
} }
// Clear the drag skeleton pointer // Clear the drag skeleton pointer
dragSkeleton = nullptr; dragSkeleton = nullptr;
// Dispose everything // Dispose everything
renderer_dispose(renderer); renderer_dispose(renderer);
delete skeletonData; delete skeletonData;
delete atlas; delete atlas;
// Kill the window and GLFW // Kill the window and GLFW
} }
spine_report_leaks(); spine_report_leaks();

View File

@ -68,7 +68,8 @@ func runSkeletonDrawableTestSwift() {
let boundsAfterPose = drawable.skeleton.bounds let boundsAfterPose = drawable.skeleton.bounds
print( print(
" Bounds after setupPose: x=\(boundsAfterPose.x), y=\(boundsAfterPose.y), width=\(boundsAfterPose.width), height=\(boundsAfterPose.height)") " Bounds after setupPose: x=\(boundsAfterPose.x), y=\(boundsAfterPose.y), width=\(boundsAfterPose.width), height=\(boundsAfterPose.height)"
)
// Test position // Test position
let position = drawable.skeleton.getPosition() let position = drawable.skeleton.getPosition()
@ -127,183 +128,185 @@ func runSkeletonDrawableTestSwift() {
drawable.update(0.5) // Update to middle of jump drawable.update(0.5) // Update to middle of jump
let boundsAfterJump = drawable.skeleton.bounds let boundsAfterJump = drawable.skeleton.bounds
print(" Bounds during jump: x=\(boundsAfterJump.x), y=\(boundsAfterJump.y), width=\(boundsAfterJump.width), height=\(boundsAfterJump.height)") print(
" Bounds during jump: x=\(boundsAfterJump.x), y=\(boundsAfterJump.y), width=\(boundsAfterJump.width), height=\(boundsAfterJump.height)"
)
// Test skin entries // Test skin entries
print("\nTesting skin entries:") print("\nTesting skin entries:")
// First, check available skins // First, check available skins
let skins = skeletonData.skins let skins = skeletonData.skins
print(" Available skins: \(skins.count)") print(" Available skins: \(skins.count)")
if skins.count > 0 { if skins.count > 0 {
// List all skin names // List all skin names
for i in 0..<skins.count { for i in 0..<skins.count {
if let skin = skins[i] { if let skin = skins[i] {
print(" Skin \(i): \(skin.name)") print(" Skin \(i): \(skin.name)")
}
}
// Set and test the first skin (or default skin)
if let defaultSkin = skins[0] {
// First get entries from the skin directly
let entriesFromData = defaultSkin.getEntries()
print(" Skin '\(defaultSkin.name)' from skeletonData has \(entriesFromData.count) entries")
// Count entries with attachments
let withAttachments = entriesFromData.filter { $0.attachment != nil }.count
print(" Entries with attachments: \(withAttachments)")
// Now set it on the skeleton
drawable.skeleton.setSkin2(defaultSkin)
drawable.skeleton.setupPoseSlots() // Update slots after setting skin
print(" Set skin on skeleton: \(defaultSkin.name)")
}
} }
}
// Set and test the first skin (or default skin) // Now test the skeleton's current skin
if let defaultSkin = skins[0] { if let skin = drawable.skeleton.skin {
// First get entries from the skin directly let entries = skin.getEntries()
let entriesFromData = defaultSkin.getEntries() print(" Skeleton's current skin has \(entries.count) entries")
print(" Skin '\(defaultSkin.name)' from skeletonData has \(entriesFromData.count) entries")
// Count entries with attachments // Show first few entries (with or without attachments for debugging)
let withAttachments = entriesFromData.filter { $0.attachment != nil }.count let entriesToShow = min(5, entries.count)
print(" Entries with attachments: \(withAttachments)") for i in 0..<entriesToShow {
let entry = entries[i]
if let attachment = entry.attachment {
let attachmentType = attachment.rtti.rttiClassName ?? "unknown"
let attachmentName = attachment.name
print(" Entry \(i): slot=\(entry.slotIndex), name=\(entry.name)")
print(" Attachment: name=\(attachmentName), type=\(attachmentType)")
} else {
print(" Entry \(i): slot=\(entry.slotIndex), name=\(entry.name), attachment=nil")
}
}
// Now set it on the skeleton // Count total entries with attachments
drawable.skeleton.setSkin2(defaultSkin) let entriesWithAttachments = entries.filter { $0.attachment != nil }.count
drawable.skeleton.setupPoseSlots() // Update slots after setting skin print(" Total entries with attachments: \(entriesWithAttachments) out of \(entries.count)")
print(" Set skin on skeleton: \(defaultSkin.name)")
}
}
// Now test the skeleton's current skin if entries.count > 3 {
if let skin = drawable.skeleton.skin { print(" ... and \(entries.count - 3) more entries")
let entries = skin.getEntries() }
print(" Skeleton's current skin has \(entries.count) entries")
// Show first few entries (with or without attachments for debugging)
let entriesToShow = min(5, entries.count)
for i in 0..<entriesToShow {
let entry = entries[i]
if let attachment = entry.attachment {
let attachmentType = attachment.rtti.rttiClassName ?? "unknown"
let attachmentName = attachment.name
print(" Entry \(i): slot=\(entry.slotIndex), name=\(entry.name)")
print(" Attachment: name=\(attachmentName), type=\(attachmentType)")
} else { } else {
print(" Entry \(i): slot=\(entry.slotIndex), name=\(entry.name), attachment=nil") print(" No skin is currently set")
} }
}
// Count total entries with attachments // Test bone pose transformations
let entriesWithAttachments = entries.filter { $0.attachment != nil }.count print("\nTesting bone pose transformations:")
print(" Total entries with attachments: \(entriesWithAttachments) out of \(entries.count)") if let rootBone = drawable.skeleton.rootBone {
// Test bone properties
let bonePose = rootBone.appliedPose
print(" Root bone: name=\(rootBone.data.name), x=\(bonePose.x), y=\(bonePose.y)")
if entries.count > 3 { // Get the bone's transform matrix from applied pose
print(" ... and \(entries.count - 3) more entries") let a = bonePose.a
} let b = bonePose.b
} else { let c = bonePose.c
print(" No skin is currently set") let d = bonePose.d
} let worldX = bonePose.worldX
let worldY = bonePose.worldY
print(" Root bone transform: a=\(a), b=\(b), c=\(c), d=\(d), worldX=\(worldX), worldY=\(worldY)")
// Test bone pose transformations // Use BonePose's built-in transformation methods
print("\nTesting bone pose transformations:") let worldPoint = Vector(x: 100, y: 100)
if let rootBone = drawable.skeleton.rootBone { let localPoint = bonePose.worldToLocal(worldX: worldPoint.x, worldY: worldPoint.y)
// Test bone properties print(" World point (100, 100) -> Local: (\(localPoint.x), \(localPoint.y))")
let bonePose = rootBone.appliedPose
print(" Root bone: name=\(rootBone.data.name), x=\(bonePose.x), y=\(bonePose.y)")
// Get the bone's transform matrix from applied pose // Test local to world transformation
let a = bonePose.a let backToWorld = bonePose.localToWorld(localX: localPoint.x, localY: localPoint.y)
let b = bonePose.b print(" Local back to world: (\(backToWorld.x), \(backToWorld.y))")
let c = bonePose.c
let d = bonePose.d
let worldX = bonePose.worldX
let worldY = bonePose.worldY
print(" Root bone transform: a=\(a), b=\(b), c=\(c), d=\(d), worldX=\(worldX), worldY=\(worldY)")
// Use BonePose's built-in transformation methods // Test rotation and scale from the pose
let worldPoint = Vector(x: 100, y: 100) let rotation = bonePose.rotation
let localPoint = bonePose.worldToLocal(worldX: worldPoint.x, worldY: worldPoint.y) let scaleX = bonePose.scaleX
print(" World point (100, 100) -> Local: (\(localPoint.x), \(localPoint.y))") let scaleY = bonePose.scaleY
print(" Bone rotation: \(rotation), scale: (\(scaleX), \(scaleY))")
// Test local to world transformation // Test parent transformation if parent exists
let backToWorld = bonePose.localToWorld(localX: localPoint.x, localY: localPoint.y) if let parentBone = rootBone.parent {
print(" Local back to world: (\(backToWorld.x), \(backToWorld.y))") let parentPose = parentBone.appliedPose
print(" Parent bone: name=\(parentBone.data.name), worldX=\(parentPose.worldX), worldY=\(parentPose.worldY)")
// Test rotation and scale from the pose // Transform world to parent coordinates
let rotation = bonePose.rotation let parentPoint = bonePose.worldToParent(worldX: worldPoint.x, worldY: worldPoint.y)
let scaleX = bonePose.scaleX print(" World point (100, 100) -> Parent: (\(parentPoint.x), \(parentPoint.y))")
let scaleY = bonePose.scaleY }
print(" Bone rotation: \(rotation), scale: (\(scaleX), \(scaleY))") }
// Test parent transformation if parent exists // Test render command
if let parentBone = rootBone.parent { print("\nTesting render command:")
let parentPose = parentBone.appliedPose if let renderCommand = drawable.render() {
print(" Parent bone: name=\(parentBone.data.name), worldX=\(parentPose.worldX), worldY=\(parentPose.worldY)") print(" Got render command with blend mode: \(renderCommand.blendMode)")
// Note: atlasPage and vertices are accessed via getters, not properties
print(" Render command received successfully")
}
// Transform world to parent coordinates // Test constraint RTTI (similar to Dart test)
let parentPoint = bonePose.worldToParent(worldX: worldPoint.x, worldY: worldPoint.y) print("\nTesting constraint RTTI:")
print(" World point (100, 100) -> Parent: (\(parentPoint.x), \(parentPoint.y))") let constraints = drawable.skeleton.constraints
} print(" Total constraints: \(constraints.count)")
} for i in 0..<constraints.count {
if let constraint = constraints[i] {
let rttiClassName = constraint.rtti.rttiClassName ?? "unknown"
print(" Constraint \(i) type: \(rttiClassName)")
// Test render command let data = constraint.data
print("\nTesting render command:") let dataRttiClassName = data.rtti.rttiClassName ?? "unknown"
if let renderCommand = drawable.render() { print(" Data type: \(dataRttiClassName)")
print(" Got render command with blend mode: \(renderCommand.blendMode)") print(" Name: \(data.name)")
// Note: atlasPage and vertices are accessed via getters, not properties }
print(" Render command received successfully") }
}
// Test constraint RTTI (similar to Dart test) // Test calling PosedActive methods on Bone instance
print("\nTesting constraint RTTI:") print("\nTesting PosedActive methods on Bone:")
let constraints = drawable.skeleton.constraints if let bone = drawable.skeleton.findBone("rear-shin") {
print(" Total constraints: \(constraints.count)") print(" Found bone: \(bone.data.name)")
for i in 0..<constraints.count {
if let constraint = constraints[i] {
let rttiClassName = constraint.rtti.rttiClassName ?? "unknown"
print(" Constraint \(i) type: \(rttiClassName)")
let data = constraint.data // Cast Bone to PosedActive and try to call PosedActive methods
let dataRttiClassName = data.rtti.rttiClassName ?? "unknown" let posedActive = bone as PosedActive
print(" Data type: \(dataRttiClassName)") print(" Successfully cast Bone to PosedActive")
print(" Name: \(data.name)")
}
}
// Test calling PosedActive methods on Bone instance // Try to access PosedActive properties/methods
print("\nTesting PosedActive methods on Bone:") // This should work if the pointer is correct, or crash if there's an offset issue
if let bone = drawable.skeleton.findBone("rear-shin") {
print(" Found bone: \(bone.data.name)")
// Cast Bone to PosedActive and try to call PosedActive methods // Get the isActive property (this is a PosedActive method)
let posedActive = bone as PosedActive let isActiveFromPosed = posedActive.isActive
print(" Successfully cast Bone to PosedActive") print(" isActive from PosedActive: \(isActiveFromPosed)")
// Try to access PosedActive properties/methods // Set active property through PosedActive
// This should work if the pointer is correct, or crash if there's an offset issue print(" Setting active to false through PosedActive...")
posedActive.active = false
print(" ✓ Set active property succeeded")
// Get the isActive property (this is a PosedActive method) // Check if it's actually false
let isActiveFromPosed = posedActive.isActive let isStillActive = posedActive.isActive
print(" isActive from PosedActive: \(isActiveFromPosed)") print(" isActive after setting to false: \(isStillActive)")
// Set active property through PosedActive // Restore it
print(" Setting active to false through PosedActive...") posedActive.active = true
posedActive.active = false print(" Restored active to true")
print(" ✓ Set active property succeeded")
// Check if it's actually false // Now test the Update protocol
let isStillActive = posedActive.isActive let updateProtocol = bone as Update
print(" isActive after setting to false: \(isStillActive)") print(" Successfully cast Bone to Update protocol")
// Restore it // Call update with required parameters
posedActive.active = true print(" Calling update() through Update protocol...")
print(" Restored active to true") updateProtocol.update(drawable.skeleton, Physics.none)
print(" ✓ update() call succeeded through Update protocol")
// Now test the Update protocol // Test that we can still use Bone methods after casting
let updateProtocol = bone as Update let appliedPose = bone.appliedPose
print(" Successfully cast Bone to Update protocol") print(" Bone appliedPose still accessible: x=\(appliedPose.x), y=\(appliedPose.y)")
// Call update with required parameters // The fact that this all works suggests the pointer is being handled correctly
print(" Calling update() through Update protocol...") // even though we're not using cast functions in the constructor chain
updateProtocol.update(drawable.skeleton, Physics.none) print(" ✓ All PosedActive and Update methods work correctly on Bone instance")
print(" ✓ update() call succeeded through Update protocol") } else {
print(" Could not find bone 'rear-shin'")
// Test that we can still use Bone methods after casting }
let appliedPose = bone.appliedPose
print(" Bone appliedPose still accessible: x=\(appliedPose.x), y=\(appliedPose.y)")
// The fact that this all works suggests the pointer is being handled correctly
// even though we're not using cast functions in the constructor chain
print(" ✓ All PosedActive and Update methods work correctly on Bone instance")
} else {
print(" Could not find bone 'rear-shin'")
}
// Clear listener before cleanup // Clear listener before cleanup
// drawable.animationState.setListener(nil) // drawable.animationState.setListener(nil)