// ---------------------------------------------------------------------------- void IKSolver::HandleComponentRemoved(StringHash eventType, VariantMap& eventData) { using namespace ComponentRemoved; if (solver_->tree == NULL) return; // If an effector was removed, the tree will have to be rebuilt. Component* component = static_cast<Component*>(eventData[P_COMPONENT].GetPtr()); if (component->GetType() == IKEffector::GetTypeStatic()) { IKEffector* effector = static_cast<IKEffector*>(component); Node* node = static_cast<Node*>(eventData[P_NODE].GetPtr()); ik_node_t* ikNode = ik_node_find_child(solver_->tree, node->GetID()); assert(ikNode != NULL); ik_node_destroy_effector(ikNode); effector->SetIKEffector(NULL); effectorList_.RemoveSwap(effector); ResetToInitialPose(); MarkSolverTreeDirty(); } // Remove the ikNode* reference the IKConstraint was holding if (component->GetType() == IKConstraint::GetTypeStatic()) { IKConstraint* constraint = static_cast<IKConstraint*>(component); constraint->SetIKNode(NULL); // NOTE: Should restore default settings to the node } }
// ---------------------------------------------------------------------------- void IKSolver::HandleNodeRemoved(StringHash eventType, VariantMap& eventData) { using namespace NodeRemoved; if (solver_->tree == NULL) return; Node* node = static_cast<Node*>(eventData[P_NODE].GetPtr()); // Remove cached IKEffectors from our list PODVector<Node*> nodes; node->GetChildrenWithComponent<IKEffector>(nodes, true); for (PODVector<Node*>::ConstIterator it = nodes.Begin(); it != nodes.End(); ++it) { IKEffector* effector = (*it)->GetComponent<IKEffector>(); effector->SetIKEffector(NULL); effectorList_.RemoveSwap(effector); } // Special case, if the node being destroyed is the root node, destroy the // solver's tree instead of destroying the single node. Calling // ik_node_destroy() on the solver's root node will cause segfaults. ik_node_t* ikNode = ik_node_find_child(solver_->tree, node->GetID()); if (ikNode != NULL) { if (ikNode == solver_->tree) ik_solver_destroy_tree(solver_); else ik_node_destroy(ikNode); MarkSolverTreeDirty(); } }
// ---------------------------------------------------------------------------- ik_node_t* IKSolver::CreateIKNodeFromUrhoNode(const Node* node) { ik_node_t* ikNode = ik_node_create(node->GetID()); // Set initial position/rotation and pass in Node* as user data for later ikNode->original_position = Vec3Urho2IK(node->GetWorldPosition()); ikNode->original_rotation = QuatUrho2IK(node->GetWorldRotation()); ikNode->user_data = (void*)node; /* * If Urho's node has an effector, also create and attach one to the * library's node. At this point, the IKEffector component shouldn't be * holding a reference to any internal effector. Check this for debugging * purposes and log if it does. */ IKEffector* effector = node->GetComponent<IKEffector>(); if (effector != nullptr) { #ifdef DEBUG if (effector->ikEffectorNode_ != NULL) URHO3D_LOGWARNINGF("[ik] IKEffector (attached to node \"%s\") has a reference to a possibly invalid internal effector. Should be NULL.", effector->GetNode()->GetName().CString()); #endif ik_effector_t* ikEffector = ik_effector_create(); ik_node_attach_effector(ikNode, ikEffector); // ownership of effector effector->SetIKSolver(this); effector->SetIKEffectorNode(ikNode); } // Exact same deal with the constraint IKConstraint* constraint = node->GetComponent<IKConstraint>(); if (constraint != nullptr) { #ifdef DEBUG if (constraint->ikConstraintNode_ != NULL) URHO3D_LOGWARNINGF("[ik] IKConstraint (attached to node \"%s\") has a reference to a possibly invalid internal constraint. Should be NULL.", constraint->GetNode()->GetName().CString()); #endif constraint->SetIKConstraintNode(ikNode); } return ikNode; }
// ---------------------------------------------------------------------------- void IKSolver::BuildTreeToEffector(const Node* node) { // Check if the component that was added is an IK effector. If not, then it // does not concern us. IKEffector* effector = static_cast<IKEffector*>(node->GetComponent<IKEffector>()); if (effector == NULL || effector->GetType() != IKEffector::GetTypeStatic()) return; // May need to build tree up to the node where this effector was added. Do // this by following the chain of parent nodes until we hit a node that // exists in the solver's tree. Then iterate backwards again and add each // missing node to the solver's tree. PODVector<const Node*> missingNodes; const Node* iterNode = node; ik_node_t* ikNode = ik_node_find_child(solver_->tree, node->GetID()); while (ikNode == NULL) { missingNodes.Push(iterNode); iterNode = iterNode->GetParent(); ikNode = ik_node_find_child(solver_->tree, iterNode->GetID()); } while (missingNodes.Size() > 0) { iterNode = missingNodes.Back(); missingNodes.Pop(); ik_node_t* ikChildNode = CreateIKNode(iterNode); ik_node_add_child(ikNode, ikChildNode); ikNode = ikChildNode; } // The tip of the tree is the effector. The solver library has ownership of // the effector object, but our IKEffector object also needs to know about // it. ik_effector_t* ikEffector = ik_effector_create(); ik_node_attach_effector(ikNode, ikEffector); // ownership of effector effector->SetIKEffector(ikEffector); // "weak" reference to effector effector->SetIKSolver(this); effectorList_.Push(effector); MarkSolverTreeDirty(); }