ValueNode_Bone::BoneSet ValueNode_Bone::get_bones_affected_by(ValueNode::Handle value_node) { BoneSet ret; set<const Node*> seen, current_nodes, new_nodes; int generation = 0; bool debug(false); if (getenv("SYNFIG_DEBUG_SUITABLE_PARENTS")) debug = true; if (debug) printf("getting bones affected by %lx %s\n", uintptr_t(value_node.get()), value_node->get_string().c_str()); // initialise current_nodes with the node we're editing current_nodes.insert(value_node.get()); do { generation++; if (debug) printf("generation %d has %zd nodes\n", generation, current_nodes.size()); int count = 0; // loop through current_nodes for (set<const Node*>::iterator iter = current_nodes.begin(); iter != current_nodes.end(); iter++, count++) { // loop through the parents of each node in current_nodes set<Node*> node_parents((*iter)->parent_set); if (debug) printf("%s:%d node %d %lx (%s) has %zd parents\n", __FILE__, __LINE__, count, uintptr_t(*iter), (*iter)->get_string().c_str(), node_parents.size()); int count2 = 0; for (set<Node*>::iterator iter2 = node_parents.begin(); iter2 != node_parents.end(); iter2++, count2++) { Node* node(*iter2); // if (debug) printf("%s:%d parent %d: %lx (%s)\n", __FILE__, __LINE__, count2, uintptr_t(node), node->get_string().c_str()); // for each parent we've not already seen if (!seen.count(node)) { // note that we've seen it now seen.insert(node); // add it to the list of new nodes to loop though in the next iteration new_nodes.insert(node); // and if it's a ValueNode_Bone, add it to the set to be returned if (dynamic_cast<ValueNode_Bone*>(node)) ret.insert(dynamic_cast<ValueNode_Bone*>(node)); } } } current_nodes = new_nodes; new_nodes.clear(); } while (current_nodes.size()); if (debug) printf("%s:%d got %zd affected bones\n", __FILE__, __LINE__, ret.size()); return ret; }
ValueNode_Bone::BoneSet ValueNode_Bone::get_possible_parent_bones(ValueNode::Handle value_node) { BoneSet ret; bool debug(false); if (getenv("SYNFIG_DEBUG_SUITABLE_PARENTS")) debug = true; if (debug) printf("%s:%d which bones can be parents of %lx (%s)\n", __FILE__, __LINE__, uintptr_t(value_node.get()), value_node->get_string().c_str()); // which bones are we currently editing the parent of - it can be more than one due to linking ValueNode_Bone::BoneSet affected_bones(ValueNode_Bone::get_bones_affected_by(value_node)); if (debug) printf("%s:%d got %zd affected bones\n", __FILE__, __LINE__, affected_bones.size()); Canvas::LooseHandle canvas(value_node->get_root_canvas()); if (debug) printf("%s:%d canvas %lx\n", __FILE__, __LINE__, uintptr_t(canvas.get())); for (ValueNode_Bone::BoneSet::iterator iter = affected_bones.begin(); iter != affected_bones.end(); iter++) { if (!canvas) { canvas = (*iter)->get_root_canvas(); printf("%s:%d root canvas %lx\n", __FILE__, __LINE__, uintptr_t((*iter)->get_root_canvas().get())); printf("%s:%d parent canvas %lx\n", __FILE__, __LINE__, uintptr_t((*iter)->get_parent_canvas().get())); printf("%s:%d ancestor canvas %lx\n", __FILE__, __LINE__, uintptr_t((*iter)->get_non_inline_ancestor_canvas().get())); } if (canvas != (*iter)->get_root_canvas()) warning("%s:%d multiple root canvases in affected bones: %lx and %lx", __FILE__, __LINE__, uintptr_t(canvas.get()), uintptr_t((*iter)->get_root_canvas().get())); } BoneMap bone_map(canvas_map[canvas]); // loop through all the bones that exist for (ValueNode_Bone::BoneMap::const_iterator iter=bone_map.begin(); iter!=bone_map.end(); iter++) { ValueNode_Bone::Handle bone_value_node(iter->second); // if the bone would be affected by our editing, skip it - it would cause a loop if the user selected it if (affected_bones.count(bone_value_node.get())) continue; // loop through the list of bones referenced by this bone's parent link; // if any of them would be affected by editing the cell, don't offer this bone in the menu { ValueNode_Bone::BoneSet parents(ValueNode_Bone::get_bones_referenced_by(bone_value_node->get_link("parent"))); ValueNode_Bone::BoneSet::iterator iter; for (iter = parents.begin(); iter != parents.end(); iter++) if (affected_bones.count(iter->get())) break; if (iter == parents.end()) ret.insert(bone_value_node); } } if (debug) printf("%s:%d returning %zd possible parents\n", __FILE__, __LINE__, ret.size()); return ret; }
ValueNode_Bone::BoneSet ValueNode_Bone::get_bones_referenced_by(ValueNode::Handle value_node, bool recursive) { // printf("%s:%d rec = %d\n", __FILE__, __LINE__,recursive); BoneSet ret; if (!value_node) { printf("%s:%d failed?\n", __FILE__, __LINE__); assert(0); return ret; } // if it's a ValueNode_Const if (ValueNode_Const::Handle value_node_const = ValueNode_Const::Handle::cast_dynamic(value_node)) { ValueBase value_node(value_node_const->get_value()); if (value_node.get_type() == type_bone_valuenode) if (ValueNode_Bone::Handle bone = value_node.get(ValueNode_Bone::Handle())) { // do we want to check for bone references in other bone fields or just 'parent'? if (recursive) { // printf("%s:%d rec\n", __FILE__, __LINE__); ret = get_bones_referenced_by(bone, recursive); // ret = get_bones_referenced_by(bone->get_link("parent"), recursive); } if (!bone->is_root()) ret.insert(bone); } return ret; } // if it's a ValueNode_Animated if (ValueNode_Animated::Handle value_node_animated = ValueNode_Animated::Handle::cast_dynamic(value_node)) { // ValueNode_Animated::Handle ret = ValueNode_Animated::create(type_bone_object); ValueNode_Animated::WaypointList list(value_node_animated->waypoint_list()); for (ValueNode_Animated::WaypointList::iterator iter = list.begin(); iter != list.end(); iter++) { // printf("%s:%d getting bones from waypoint\n", __FILE__, __LINE__); BoneSet ret2(get_bones_referenced_by(iter->get_value_node(), recursive)); ret.insert(ret2.begin(), ret2.end()); // printf("added %d bones from waypoint to get %d\n", int(ret2.size()), int(ret.size())); } // printf("returning %d bones\n", int(ret.size())); return ret; } // if it's a LinkableValueNode if (LinkableValueNode::Handle linkable_value_node = LinkableValueNode::Handle::cast_dynamic(value_node)) { for (int i = 0; i < linkable_value_node->link_count(); i++) { BoneSet ret2(get_bones_referenced_by(linkable_value_node->get_link(i), recursive)); ret.insert(ret2.begin(), ret2.end()); } return ret; } if (PlaceholderValueNode::Handle linkable_value_node = PlaceholderValueNode::Handle::cast_dynamic(value_node)) { // todo: while loading we might be setting up an ancestry loop by ignoring the placeholder valuenode here // can we check for loops in badly formatted .sifz files somehow? if (getenv("SYNFIG_DEBUG_PLACEHOLDER_VALUENODE")) printf("%s:%d found a placeholder - skipping loop check\n", __FILE__, __LINE__); return ret; } error("%s:%d BUG: bad type in valuenode '%s'", __FILE__, __LINE__, value_node->get_string().c_str()); assert(0); return ret; }