From 03d0687311185d16a23ef71c7dc1e2fca754c742 Mon Sep 17 00:00:00 2001 From: Sergey Kazantsev Date: Sat, 11 Feb 2023 14:15:14 +0100 Subject: [PATCH] Add "set_bone_position" API method --- defold-spine/src/comp_spine_model.cpp | 18 ++++++++++++ defold-spine/src/comp_spine_model.h | 2 ++ defold-spine/src/res_spine_scene.cpp | 11 +++++++ defold-spine/src/res_spine_scene.h | 1 + defold-spine/src/script_spine.cpp | 42 +++++++++++++++++++++++++++ 5 files changed, 74 insertions(+) diff --git a/defold-spine/src/comp_spine_model.cpp b/defold-spine/src/comp_spine_model.cpp index aa81b58..a754ac6 100644 --- a/defold-spine/src/comp_spine_model.cpp +++ b/defold-spine/src/comp_spine_model.cpp @@ -1396,6 +1396,24 @@ namespace dmSpine *instance_id = dmGameObject::GetIdentifier(bone_instance); return true; } + + bool CompSpineModelSetBonePosition(SpineModelComponent* component, dmhash_t bone_name, Point3 position) + { + SpineModelResource* spine_model = component->m_Resource; + SpineSceneResource* spine_scene = spine_model->m_SpineScene; + uint32_t* index = spine_scene->m_BoneNameToIndex.Get(bone_name); + + if (!index) + return false; + + spBone* bone = component->m_SkeletonInstance->bones[*index]; + dmVMath::Vector3 model_pos = (dmVMath::Vector3)dmTransform::Apply(dmTransform::Inv(dmTransform::Mul(dmGameObject::GetWorldTransform(component->m_Instance), component->m_Transform)), position); + + bone->x = model_pos.getX(); + bone->y = model_pos.getY(); + + return true; + } } DM_DECLARE_COMPONENT_TYPE(ComponentTypeSpineModelExt, "spinemodelc", dmSpine::CompTypeSpineModelCreate, dmSpine::CompTypeSpineModelDestroy); diff --git a/defold-spine/src/comp_spine_model.h b/defold-spine/src/comp_spine_model.h index dbb76c3..27c8abc 100644 --- a/defold-spine/src/comp_spine_model.h +++ b/defold-spine/src/comp_spine_model.h @@ -97,6 +97,8 @@ namespace dmSpine bool CompSpineModelGetBone(SpineModelComponent* component, dmhash_t bone_name, dmhash_t* instance_id); + bool CompSpineModelSetBonePosition(SpineModelComponent* component, dmhash_t bone_name, Vectormath::Aos::Point3 position); + } #endif // DM_GAMESYS_COMP_SPINE_MODEL_H diff --git a/defold-spine/src/res_spine_scene.cpp b/defold-spine/src/res_spine_scene.cpp index f0e48c6..b23739c 100644 --- a/defold-spine/src/res_spine_scene.cpp +++ b/defold-spine/src/res_spine_scene.cpp @@ -114,6 +114,17 @@ namespace dmSpine } } + { + uint32_t count = resource->m_Skeleton->bonesCount; + resource->m_BoneNameToIndex.SetCapacity(dmMath::Max(1U, count/3), count); + for (int n = 0; n < count; ++n) + { + dmhash_t name_hash = dmHashString64(resource->m_Skeleton->bones[n]->name); + resource->m_BoneNameToIndex.Put(name_hash, n); + DEBUGLOG("bone: %d %s", n, resource->m_Skeleton->bones[n]->name); + } + } + return dmResource::RESULT_OK; } diff --git a/defold-spine/src/res_spine_scene.h b/defold-spine/src/res_spine_scene.h index 29371b9..805a5b3 100644 --- a/defold-spine/src/res_spine_scene.h +++ b/defold-spine/src/res_spine_scene.h @@ -34,6 +34,7 @@ namespace dmSpine dmHashTable64 m_SkinNameToIndex; dmHashTable64 m_SlotNameToIndex; dmHashTable64 m_IKNameToIndex; + dmHashTable64 m_BoneNameToIndex; dmHashTable64 m_AttachmentHashToName; // makes it easy for us to do a reverse hash for attachments }; } diff --git a/defold-spine/src/script_spine.cpp b/defold-spine/src/script_spine.cpp index 6ebb2fa..89b01ce 100644 --- a/defold-spine/src/script_spine.cpp +++ b/defold-spine/src/script_spine.cpp @@ -679,6 +679,47 @@ namespace dmSpine return 0; } + /*# Set world space bone position + * Note that bones positions will be overwritten by active animations and constraints(IK, Path, Transform...), only change positions of bones that is not affected by those. + * + * @name spine.get_go + * @param url [type:string|hash|url] the spine model to query + * @param bone_id [type:string|hash] id of the corresponding bone + * @param position [type:vector3] position in world space + * @examples + * + * The following examples assumes that the spine model has id "spinemodel" and it has bone named "crosshair" + * + * How to set bone position to mouse position("crosshair" could be IK target for example): + * + * ```lua + * function on_input(self) + * if action_id == nil then + * spine.set_bone_position("#spinemodel", "crosshair", vmath.vector3(action.x, action.y, 0)) + * end + * end + * ``` + */ + static int SpineComp_SetBonePosition(lua_State* L) + { + DM_LUA_STACK_CHECK(L, 0); + + SpineModelComponent* component = 0; + dmMessage::URL receiver; // needed for error output + dmGameObject::GetComponentFromLua(L, 1, SPINE_MODEL_EXT, 0, (void**)&component, &receiver); + + dmhash_t bone_id = dmScript::CheckHashOrString(L, 2); + Vectormath::Aos::Vector3* position = dmScript::CheckVector3(L, 3); + + if (!CompSpineModelSetBonePosition(component, bone_id, (Point3)*position)) + { + char buffer[128]; + return DM_LUA_ERROR("the bone '%s' could not be found in component %s", lua_tostring(L, 2), dmScript::UrlToString(&receiver, buffer, sizeof(buffer))); + } + + return 0; + } + /** Deprecated: set a shader constant for a spine model * Sets a shader constant for a spine model component. * The constant must be defined in the material assigned to the spine model. @@ -780,6 +821,7 @@ namespace dmSpine {"set_ik_target_position", SpineComp_SetIKTargetPosition}, {"set_ik_target", SpineComp_SetIKTarget}, {"reset_ik_target", SpineComp_ResetIK}, + {"set_bone_position", SpineComp_SetBonePosition}, {"set_constant", SpineComp_SetConstant}, {"reset_constant", SpineComp_ResetConstant}, {0, 0}