void postEditBoneDuplicate(struct ListBase *editbones, Object *ob) { if (ob->pose == NULL) { return; } BKE_pose_channels_hash_free(ob->pose); BKE_pose_channels_hash_make(ob->pose); GHash *name_map = BLI_ghash_str_new(__func__); for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) { EditBone *ebone_dst = ebone_src->temp.ebone; if (!ebone_dst) { ebone_dst = ED_armature_bone_get_mirrored(editbones, ebone_src); } if (ebone_dst) { BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name); } } for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) { EditBone *ebone_dst = ebone_src->temp.ebone; if (ebone_dst) { bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name); if (pchan_src) { bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name); if (pchan_dst) { if (pchan_src->custom_tx) { pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx); } if (pchan_src->bbone_prev) { pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev); } if (pchan_src->bbone_next) { pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next); } } } } } BLI_ghash_free(name_map, NULL, NULL); }
/** * Move here pose function for game engine so that we can mix with GE objects * Principle is as follow: * Use Blender structures so that BKE_pose_where_is can be used unchanged * Copy the constraint so that they can be enabled/disabled/added/removed at runtime * Don't copy the constraints for the pose used by the Action actuator, it does not need them. * Scan the constraint structures so that the KX equivalent of target objects are identified and * stored in separate list. * When it is about to evaluate the pose, set the KX object position in the obmat of the corresponding * Blender objects and restore after the evaluation. */ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) { bPose *out; bPoseChannel *pchan, *outpchan; GHash *ghash; /* the game engine copies the current armature pose and then swaps * the object pose pointer. this makes it possible to change poses * without affecting the original blender data. */ if (!src) { *dst=NULL; return; } else if (*dst==src) { printf("game_copy_pose source and target are the same\n"); *dst=NULL; return; } out= (bPose*)MEM_dupallocN(src); out->chanhash = NULL; out->agroups.first= out->agroups.last= NULL; out->ikdata = NULL; out->ikparam = MEM_dupallocN(src->ikparam); out->flag |= POSE_GAME_ENGINE; BLI_duplicatelist(&out->chanbase, &src->chanbase); /* remap pointers */ ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "game_copy_pose gh"); pchan= (bPoseChannel *)src->chanbase.first; outpchan= (bPoseChannel *)out->chanbase.first; for (; pchan; pchan=pchan->next, outpchan=outpchan->next) BLI_ghash_insert(ghash, pchan, outpchan); for (pchan = (bPoseChannel *)out->chanbase.first; pchan; pchan = pchan->next) { pchan->parent= (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->parent); pchan->child= (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->child); if (copy_constraint) { ListBase listb; // copy all constraint for backward compatibility // BKE_constraints_copy NULLs listb, no need to make extern for this operation. BKE_constraints_copy(&listb, &pchan->constraints, false); pchan->constraints= listb; } else { BLI_listbase_clear(&pchan->constraints); } if (pchan->custom) { id_us_plus(&pchan->custom->id); } // fails to link, props are not used in the BGE yet. #if 0 if (pchan->prop) pchan->prop= IDP_CopyProperty(pchan->prop); #endif pchan->prop= NULL; } BLI_ghash_free(ghash, NULL, NULL); // set acceleration structure for channel lookup BKE_pose_channels_hash_make(out); *dst=out; }
/** * Allocate a new pose on the heap, and copy the src pose and it's channels * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL. * * \param dst Should be freed already, makes entire duplicate. */ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints) { bPose *outPose; bPoseChannel *pchan; ListBase listb; if (!src) { *dst = NULL; return; } outPose = MEM_callocN(sizeof(bPose), "pose"); BLI_duplicatelist(&outPose->chanbase, &src->chanbase); /* Rebuild ghash here too, so that name lookups below won't be too bad... * BUT this will have the penalty that the ghash will be built twice * if BKE_pose_rebuild() gets called after this... */ if (outPose->chanbase.first != outPose->chanbase.last) { outPose->chanhash = NULL; BKE_pose_channels_hash_make(outPose); } outPose->iksolver = src->iksolver; outPose->ikdata = NULL; outPose->ikparam = MEM_dupallocN(src->ikparam); outPose->avs = src->avs; for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->custom) { id_us_plus(&pchan->custom->id); } /* warning, O(n2) here, if done without the hash, but these are rarely used features. */ if (pchan->custom_tx) { pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name); } if (pchan->bbone_prev) { pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name); } if (pchan->bbone_next) { pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name); } if (copy_constraints) { BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } if (pchan->prop) { pchan->prop = IDP_CopyProperty(pchan->prop); } } /* for now, duplicate Bone Groups too when doing this */ if (copy_constraints) { BLI_duplicatelist(&outPose->agroups, &src->agroups); } *dst = outPose; }
/* For the calculation of the effects of an Action at the given frame on an object * This is currently only used for the Action Constraint */ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe) { bActionGroup *agrp = BKE_action_group_find_name(act, groupname); /* clear workob */ BKE_object_workob_clear(workob); /* init workob */ copy_m4_m4(workob->obmat, ob->obmat); copy_m4_m4(workob->parentinv, ob->parentinv); copy_m4_m4(workob->constinv, ob->constinv); workob->parent = ob->parent; workob->rotmode = ob->rotmode; workob->trackflag = ob->trackflag; workob->upflag = ob->upflag; workob->partype = ob->partype; workob->par1 = ob->par1; workob->par2 = ob->par2; workob->par3 = ob->par3; workob->constraints.first = ob->constraints.first; workob->constraints.last = ob->constraints.last; workob->pose = pose; /* need to set pose too, since this is used for both types of Action Constraint */ if (pose) { /* This function is most likely to be used with a temporary pose with a single bone in there. * For such cases it makes no sense to create hash since it'll only waste CPU ticks on memory * allocation and also will make lookup slower. */ if (pose->chanbase.first != pose->chanbase.last) { BKE_pose_channels_hash_make(pose); } if (pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { BKE_pose_update_constraint_flags(pose); } } BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr)); BLI_strncpy(workob->id.name, "OB<ConstrWorkOb>", sizeof(workob->id.name)); /* we don't use real object name, otherwise RNA screws with the real thing */ /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */ if (agrp) { /* specifically evaluate this group only */ PointerRNA id_ptr; /* get RNA-pointer for the workob's ID */ RNA_id_pointer_create(&workob->id, &id_ptr); /* execute action for this group only */ animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe); } else { AnimData adt = {NULL}; /* init animdata, and attach to workob */ workob->adt = &adt; adt.recalc = ADT_RECALC_ANIM; adt.action = act; /* execute effects of Action on to workob (or it's PoseChannels) */ BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM); } }