void MemoryTestFixture::reproduceIssue_Loop() { spAtlas* atlas = nullptr; spSkeletonData* skeletonData = nullptr; spAnimationStateData* stateData = nullptr; spAnimationState* state = nullptr; ////////////////////////////////////////////////////////////////////////// // Initialize Animations LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state); /////////////////////////////////////////////////////////////////////////// if (state) state->listener = (spAnimationStateListener)&spineAnimStateHandler; spAnimationState_setAnimationByName(state, 0, "walk", false); // run normal update for (int i = 0; i < 50; ++i) { const float timeSlice = 1.0f / 60.0f; spSkeleton_update(skeleton, timeSlice); spAnimationState_update(state, timeSlice); spAnimationState_apply(state, skeleton); } DisposeAll(skeleton, state, stateData, skeletonData, atlas); }
void SkeletonAnimationFbo::updateSkeletonAnimation() { if (!isSkeletonValid()) { update(); return; } if (!mEventCache.isEmpty()){ Q_FOREACH(SpineEvent* event, mEventCache) SAFE_DELETE(event); mEventCache.clear(); } qint64 mSecs = 0; if (!mTimer.isValid()) mTimer.start(); else mSecs = mTimer.restart(); const float deltaTime = mSecs/1000.0 * mTimeScale; spSkeleton_update(mspSkeleton, deltaTime); spAnimationState_update(mspAnimationState, deltaTime); spAnimationState_apply(mspAnimationState, mspSkeleton); spSkeleton_updateWorldTransform(mspSkeleton); const QRectF rect = calculateSkeletonRect(); setSourceSize(QSize(rect.width(), rect.height())); setImplicitSize(rect.width(), rect.height()); setPosition(QPointF(rect.left(), -1.0f*(rect.top() + rect.height()))); update(); }
void MemoryTestFixture::reproduceIssue_777() { spAtlas* atlas = nullptr; spSkeletonData* skeletonData = nullptr; spAnimationStateData* stateData = nullptr; spSkeleton* skeleton = nullptr; spAnimationState* state = nullptr; ////////////////////////////////////////////////////////////////////////// // Initialize Animations LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state); /////////////////////////////////////////////////////////////////////////// // Run animation spSkeleton_setToSetupPose(skeleton); SpineEventMonitor eventMonitor(state); //eventMonitor.SetDebugLogging(true); // Set Animation and Play for 5 frames spAnimationState_setAnimationByName(state, 0, "walk", true); for (int i = 0; i < 5; ++i) { const float timeSlice = 1.0f / 60.0f; spSkeleton_update(skeleton, timeSlice); spAnimationState_update(state, timeSlice); spAnimationState_apply(state, skeleton); } // Change animation twice in a row spAnimationState_setAnimationByName(state, 0, "walk", false); spAnimationState_setAnimationByName(state, 0, "run", false); // run normal update for (int i = 0; i < 5; ++i) { const float timeSlice = 1.0f / 60.0f; spSkeleton_update(skeleton, timeSlice); spAnimationState_update(state, timeSlice); spAnimationState_apply(state, skeleton); } // Now we'd lose mixingFrom (the first "walk" entry we set above) and should leak spAnimationState_setAnimationByName(state, 0, "run", false); ////////////////////////////////////////////////////////////////////////// // Cleanup Animations DisposeAll(skeleton, state, stateData, skeletonData, atlas); }
static void testRunner(const char* jsonName, const char* atlasName) { /////////////////////////////////////////////////////////////////////////// // Global Animation Information spAtlas* atlas = spAtlas_createFromFile(atlasName, 0); ASSERT(atlas != 0); spSkeletonData* skeletonData = readSkeletonJsonData(jsonName, atlas); ASSERT(skeletonData != 0); spAnimationStateData* stateData = spAnimationStateData_create(skeletonData); ASSERT(stateData != 0); stateData->defaultMix = 0.2f; // force mixing /////////////////////////////////////////////////////////////////////////// // Animation Instance spSkeleton* skeleton = spSkeleton_create(skeletonData); ASSERT(skeleton != 0); spAnimationState* state = spAnimationState_create(stateData); ASSERT(state != 0); /////////////////////////////////////////////////////////////////////////// // Run animation spSkeleton_setToSetupPose(skeleton); SpineEventMonitor eventMonitor(state); // eventMonitor.SetDebugLogging(true); AnimList anims; // Let's chain all the animations together as a test size_t count = enumerateAnimations(anims, skeletonData); if (count > 0) spAnimationState_setAnimationByName(state, 0, anims[0].c_str(), false); for (size_t i = 1; i < count; ++i) { spAnimationState_addAnimationByName(state, 0, anims[i].c_str(), false, 0.0f); } // Run Loop for (int i = 0; i < MAX_RUN_TIME && eventMonitor.isAnimationPlaying(); ++i) { const float timeSlice = 1.0f / 60.0f; spSkeleton_update(skeleton, timeSlice); spAnimationState_update(state, timeSlice); spAnimationState_apply(state, skeleton); } /////////////////////////////////////////////////////////////////////////// // Dispose Instance spSkeleton_dispose(skeleton); spAnimationState_dispose(state); /////////////////////////////////////////////////////////////////////////// // Dispose Global spAnimationStateData_dispose(stateData); spSkeletonData_dispose(skeletonData); spAtlas_dispose(atlas); }
////////////////////////////////////////////////////////////////////////// // Reproduce Memory leak as described in Issue #776 // https://github.com/EsotericSoftware/spine-runtimes/issues/776 void MemoryTestFixture::reproduceIssue_776() { spAtlas* atlas = nullptr; spSkeletonData* skeletonData = nullptr; spAnimationStateData* stateData = nullptr; spSkeleton* skeleton = nullptr; spAnimationState* state = nullptr; ////////////////////////////////////////////////////////////////////////// // Initialize Animations LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state); /////////////////////////////////////////////////////////////////////////// // Run animation spSkeleton_setToSetupPose(skeleton); InterruptMonitor eventMonitor(state); //eventMonitor.SetDebugLogging(true); // Interrupt the animation on this specific sequence of spEventType(s) eventMonitor .AddInterruptEvent(SP_ANIMATION_INTERRUPT, "jump") .AddInterruptEvent(SP_ANIMATION_START); spAnimationState_setAnimationByName(state, 0, "walk", true); spAnimationState_addAnimationByName(state, 0, "jump", false, 0.0f); spAnimationState_addAnimationByName(state, 0, "run", true, 0.0f); spAnimationState_addAnimationByName(state, 0, "jump", false, 3.0f); spAnimationState_addAnimationByName(state, 0, "walk", true, 0.0f); spAnimationState_addAnimationByName(state, 0, "idle", false, 1.0f); for (int i = 0; i < MAX_RUN_TIME && eventMonitor.isAnimationPlaying(); ++i) { const float timeSlice = 1.0f / 60.0f; spSkeleton_update(skeleton, timeSlice); spAnimationState_update(state, timeSlice); spAnimationState_apply(state, skeleton); } ////////////////////////////////////////////////////////////////////////// // Cleanup Animations DisposeAll(skeleton, state, stateData, skeletonData, atlas); }
ENTITY_COMPONENT_METHOD(ComponentSpine, update) { if(!self.skeleton) { return 0; } auto dt = System::getInstance().getCurrentDt(); auto & mesh = self.mesh; Transform transform; getTransformFromComponent(state, transform); mesh.setPosition(transform.position); mesh.setRotation(transform.rotation); mesh.setScale(transform.scale); spSkeleton_update(self.skeleton, dt * self.timeFactor); spAnimationState_update(self.animationState, dt * self.timeFactor); spAnimationState_apply(self.animationState, self.skeleton); spSkeleton_updateWorldTransform(self.skeleton); auto vertices = self.mesh.getVertexBuffer().map(); auto indices = self.mesh.getIndexBuffer().map(); uint vertex_count = 0; uint index_count = 0; for(int i = 0; i < self.skeleton->slotsCount; ++i) { auto slot = self.skeleton->drawOrder[i]; auto attachment = slot->attachment; if(!attachment) { continue; } switch(attachment->type) { case SP_ATTACHMENT_REGION: { Vector2 computed_vertices[4]; auto region_attachment = (spRegionAttachment*)attachment; auto color = Vector4( self.skeleton->r * slot->r, self.skeleton->g * slot->g, self.skeleton->b * slot->b, self.skeleton->a * slot->a ); self.mesh.setTexture(* (graphics::Texture*)((spAtlasRegion*)region_attachment->rendererObject)->page->rendererObject); spRegionAttachment_computeWorldVertices(region_attachment, slot->bone, (float *)computed_vertices); vertices[vertex_count].color = color; vertices[vertex_count].position = computed_vertices[0]; vertices[vertex_count].texCoords.x = region_attachment->uvs[SP_VERTEX_X1]; vertices[vertex_count].texCoords.y = region_attachment->uvs[SP_VERTEX_Y1]; vertices[vertex_count + 1].color = color; vertices[vertex_count + 1].position = computed_vertices[1]; vertices[vertex_count + 1].texCoords.x = region_attachment->uvs[SP_VERTEX_X2]; vertices[vertex_count + 1].texCoords.y = region_attachment->uvs[SP_VERTEX_Y2]; vertices[vertex_count + 2].color = color; vertices[vertex_count + 2].position = computed_vertices[2]; vertices[vertex_count + 2].texCoords.x = region_attachment->uvs[SP_VERTEX_X3]; vertices[vertex_count + 2].texCoords.y = region_attachment->uvs[SP_VERTEX_Y3]; vertices[vertex_count + 3].color = color; vertices[vertex_count + 3].position = computed_vertices[3]; vertices[vertex_count + 3].texCoords.x = region_attachment->uvs[SP_VERTEX_X4]; vertices[vertex_count + 3].texCoords.y = region_attachment->uvs[SP_VERTEX_Y4]; indices[index_count + 0] = vertex_count + 0; indices[index_count + 1] = vertex_count + 1; indices[index_count + 2] = vertex_count + 2; indices[index_count + 3] = vertex_count + 2; indices[index_count + 4] = vertex_count + 3; indices[index_count + 5] = vertex_count + 0; vertex_count += 4; index_count += 6; } break; case SP_ATTACHMENT_MESH: { auto mesh = (spMeshAttachment*)attachment; auto initial_vertex_count = vertex_count; auto color = Vector4( self.skeleton->r * slot->r, self.skeleton->g * slot->g, self.skeleton->b * slot->b, self.skeleton->a * slot->a ); float *_vertices = mesh->vertices; const spBone* bone = slot->bone; float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY; self.mesh.setTexture(* (graphics::Texture*)((spAtlasRegion*)mesh->rendererObject)->page->rendererObject); if(slot->attachmentVerticesCount == mesh->verticesCount) { _vertices = slot->attachmentVertices; } for(int i = 0; i < mesh->verticesCount; i += 2) { const float vx = _vertices[i], vy = _vertices[i + 1]; auto & vertex = vertices[initial_vertex_count + i / 2]; vertex.position.x = vx * bone->m00 + vy * bone->m01 + x; vertex.position.y = vx * bone->m10 + vy * bone->m11 + y; vertex.texCoords.u = mesh->uvs[i]; vertex.texCoords.v = mesh->uvs[i + 1]; vertex.color = color; ++vertex_count; } for(int i = 0; i < mesh->trianglesCount; ++i) { int index = mesh->triangles[i] << 1; indices[index_count] = initial_vertex_count + index / 2; ++index_count; } } break; case SP_ATTACHMENT_SKINNED_MESH: { auto mesh = (spSkinnedMeshAttachment*)attachment; auto initial_vertex_count = vertex_count; auto color = Vector4( self.skeleton->r * slot->r, self.skeleton->g * slot->g, self.skeleton->b * slot->b, self.skeleton->a * slot->a ); self.mesh.setTexture(* (graphics::Texture*)((spAtlasRegion*)mesh->rendererObject)->page->rendererObject); int w = 0, v = 0, b = 0, f = 0; float x = slot->bone->skeleton->x, y = slot->bone->skeleton->y; spBone** skeletonBones = slot->bone->skeleton->bones; if(slot->attachmentVerticesCount == 0) { for(; v < mesh->bonesCount; w += 2) { float wx = 0, wy = 0; const int nn = mesh->bones[v] + v; v++; for(; v <= nn; v++, b += 3) { const spBone* bone = skeletonBones[mesh->bones[v]]; const float vx = mesh->weights[b], vy = mesh->weights[b + 1], weight = mesh->weights[b + 2]; wx += (vx * bone->m00 + vy * bone->m01 + bone->worldX) * weight; wy += (vx * bone->m10 + vy * bone->m11 + bone->worldY) * weight; } auto & vertex = vertices[initial_vertex_count + w / 2]; ++vertex_count; vertex.position.x = wx + x; vertex.position.y = wy + y; vertex.texCoords.u = mesh->uvs[w]; vertex.texCoords.v = mesh->uvs[w + 1]; vertex.color = color; } } else { const float* ffd = slot->attachmentVertices; for(; v < mesh->bonesCount; w += 2) { float wx = 0, wy = 0; const int nn = mesh->bones[v] + v; v++; for(; v <= nn; v++, b += 3, f += 2) { const spBone* bone = skeletonBones[mesh->bones[v]]; const float vx = mesh->weights[b] + ffd[f], vy = mesh->weights[b + 1] + ffd[f + 1], weight = mesh->weights[b + 2]; wx += (vx * bone->m00 + vy * bone->m01 + bone->worldX) * weight; wy += (vx * bone->m10 + vy * bone->m11 + bone->worldY) * weight; } auto & vertex = vertices[initial_vertex_count + w / 2]; ++vertex_count; vertex.position.x = wx + x; vertex.position.y = wy + y; vertex.texCoords.u = mesh->uvs[w]; vertex.texCoords.v = mesh->uvs[w + 1]; vertex.color = color; } } for(int i = 0; i < mesh->trianglesCount; ++i) { int index = mesh->triangles[i] << 1; indices[index_count] = initial_vertex_count + index / 2; ++index_count; } } break; default: break; } } self.mesh.setVertexCount(vertex_count); self.mesh.setIndexCount(index_count); self.mesh.getVertexBuffer().unMap(); self.mesh.getIndexBuffer().unMap(); }
void WIPAnimator::update(f32 dt) { if(!_frame_ref) return; f32 iww = 1.f/g_app_manager->get_window_width(); f32 iwh = 1.f/g_app_manager->get_window_height(); f32 sw = _out_buffer->get_width()*iww; f32 sh = _out_buffer->get_height()*iwh; f32 hw =g_app_manager->get_window_width()*0.5f; f32 hh = g_app_manager->get_window_height()*0.65f; _out_buffer->begin(); glClear(GL_COLOR_BUFFER_BIT); _out_buffer->end(); spSkeleton_update(skeleton, dt); spAnimationState_update(state, dt * time_scale); spAnimationState_apply(state, skeleton); spSkeleton_updateWorldTransform(skeleton); _out_buffer->begin(); for(int i=0;i<skeleton->slotCount; ++i) { spSlot* slot = skeleton->drawOrder[i]; spAttachment* attachment = slot->attachment; if (!attachment) continue; WIPTexture* p = 0; if (attachment->type == SP_ATTACHMENT_REGION) { //available spRegionAttachment* regionAttachment = (spRegionAttachment*)attachment; p = (WIPTexture*)((spAtlasRegion*)regionAttachment->rendererObject)->page->rendererObject; spRegionAttachment_computeWorldVertices(regionAttachment, slot->skeleton->x, slot->skeleton->y,slot->bone, _world_vertices); } if(p) { spRegionAttachment* regionAttachment = (spRegionAttachment*)attachment; int tex_x = p->get_width(); int tex_y = p->get_height(); RenderQuad uv_q; uv_q.lt.x = regionAttachment->uvs[SP_VERTEX_X1]; uv_q.lt.y =regionAttachment->uvs[SP_VERTEX_Y1]; uv_q.lb.x = regionAttachment->uvs[SP_VERTEX_X2]; uv_q.lb.y =regionAttachment->uvs[SP_VERTEX_Y2]; uv_q.rt.x = regionAttachment->uvs[SP_VERTEX_X4]; uv_q.rt.y =regionAttachment->uvs[SP_VERTEX_Y4]; uv_q.rb.x = regionAttachment->uvs[SP_VERTEX_X3]; uv_q.rb.y =regionAttachment->uvs[SP_VERTEX_Y3]; int x1 = _world_vertices[SP_VERTEX_X1]; int y1 = _world_vertices[SP_VERTEX_Y1]; int x2 = _world_vertices[SP_VERTEX_X2]; int y2 = _world_vertices[SP_VERTEX_Y2]; int x4 = _world_vertices[SP_VERTEX_X3]; int y4 = _world_vertices[SP_VERTEX_Y3]; int x3 = _world_vertices[SP_VERTEX_X4]; int y3 = _world_vertices[SP_VERTEX_Y4]; RenderQuad q; q.lb.x = x1+hw; q.lb.y = y1+hh; q.lt.x = x2+hw; q.lt.y = y2+hh; q.rb.x = x3+hw; q.rb.y = y3+hh; q.rt.x = x4+hw; q.rt.y = y4+hh; g_renderer->render(p,&q,&uv_q); } } _out_buffer->end(); _frame_ref->texture = _out_buffer; _frame_ref->framebox->set_quickly(0,0,0,1,1,1,1,0,0,0); }
void SkeletonRenderer::update (float deltaTime) { spSkeleton_update(_skeleton, deltaTime * _timeScale); }
void Skeleton::update (float deltaTime) { spSkeleton_update(skeleton, deltaTime * timeScale); }
void Skeleton::update(unsigned long dt) { const float delta = dt / 1000.0f; spSkeleton_update(skeleton_, delta); spAnimationState_update(state_, delta * time_scale_); spAnimationState_apply(state_, skeleton_); spSkeleton_updateWorldTransform(skeleton_); // This solution is not ideal. We iterate over the bones twice: First to // determine number of vertices, second to update the vertex buffer. num_vertices_ = get_vertex_count(skeleton_, &texture_); if (num_vertices_ > max_vertices_) { max_vertices_ = num_vertices_; vertices_ = std::make_unique<SpriteVertex[]>(max_vertices_); } size_t i = 0; for_each(skeleton_, [this, &i](spSlot* slot) { if (!slot->attachment) return; switch (slot->attachment->type) { case SP_ATTACHMENT_REGION: { float vertices[8]; spRegionAttachment* region = reinterpret_cast<spRegionAttachment*>(slot->attachment); R_ASSERT(texture_ == get_texture(region), kErrorMultipleTexturesUnsupported); spRegionAttachment_computeWorldVertices( region, slot->bone, vertices); const char r = skeleton_->r * slot->r * 0xff; const char g = skeleton_->g * slot->g * 0xff; const char b = skeleton_->b * slot->b * 0xff; const char a = skeleton_->a * slot->a * 0xff; vertices_[i].color.r = r; vertices_[i].color.g = g; vertices_[i].color.b = b; vertices_[i].color.a = a; vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X1]; vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y1]; vertices_[i].position.x = vertices[SP_VERTEX_X1]; vertices_[i].position.y = vertices[SP_VERTEX_Y1]; vertices_[++i].color.r = r; vertices_[i].color.g = g; vertices_[i].color.b = b; vertices_[i].color.a = a; vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X2]; vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y2]; vertices_[i].position.x = vertices[SP_VERTEX_X2]; vertices_[i].position.y = vertices[SP_VERTEX_Y2]; vertices_[++i].color.r = r; vertices_[i].color.g = g; vertices_[i].color.b = b; vertices_[i].color.a = a; vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X3]; vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y3]; vertices_[i].position.x = vertices[SP_VERTEX_X3]; vertices_[i].position.y = vertices[SP_VERTEX_Y3]; ++i; vertices_[i] = vertices_[i - 1]; vertices_[++i].color.r = r; vertices_[i].color.g = g; vertices_[i].color.b = b; vertices_[i].color.a = a; vertices_[i].texcoord.x = region->uvs[SP_VERTEX_X4]; vertices_[i].texcoord.y = region->uvs[SP_VERTEX_Y4]; vertices_[i].position.x = vertices[SP_VERTEX_X4]; vertices_[i].position.y = vertices[SP_VERTEX_Y4]; ++i; vertices_[i] = vertices_[i - 5]; ++i; break; } case SP_ATTACHMENT_BOUNDING_BOX: break; case SP_ATTACHMENT_MESH: { spMeshAttachment* mesh = reinterpret_cast<spMeshAttachment*>(slot->attachment); R_ASSERT(texture_ == get_texture(mesh), kErrorMultipleTexturesUnsupported); i += update_mesh(&vertices_[i], skeleton_, mesh, slot); break; } case SP_ATTACHMENT_SKINNED_MESH: { spSkinnedMeshAttachment* mesh = reinterpret_cast<spSkinnedMeshAttachment*>( slot->attachment); R_ASSERT(texture_ == get_texture(mesh), kErrorMultipleTexturesUnsupported); i += update_mesh(&vertices_[i], skeleton_, mesh, slot); break; } } if (slot->data->blendMode != SP_BLEND_MODE_NORMAL) // TODO: Implement. LOGE("Non-normal blend mode not yet implemented"); }); vertex_buffer_.upload(vertices_.get(), i * sizeof(SpriteVertex)); }
void SpineDrawable::update(float delta) { spSkeleton_update(skeleton, delta); spAnimationState_update(animationState, delta); }
void SkeletonDrawable::update (float deltaTime) { spSkeleton_update(skeleton, deltaTime); spAnimationState_update(state, deltaTime * timeScale); spAnimationState_apply(state, skeleton); spSkeleton_updateWorldTransform(skeleton); }