2631 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2631 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * ***** BEGIN GPL LICENSE BLOCK *****
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public License
 | 
						|
 * as published by the Free Software Foundation; either version 2
 | 
						|
 * of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 * Contributor(s): Martin Poirier
 | 
						|
 *
 | 
						|
 * ***** END GPL LICENSE BLOCK *****
 | 
						|
 * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...)
 | 
						|
 */
 | 
						|
 | 
						|
/** \file blender/editors/armature/editarmature_retarget.c
 | 
						|
 *  \ingroup edarmature
 | 
						|
 */
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
#include "PIL_time.h"
 | 
						|
 | 
						|
#include "DNA_armature_types.h"
 | 
						|
#include "DNA_constraint_types.h"
 | 
						|
#include "DNA_scene_types.h"
 | 
						|
#include "DNA_object_types.h"
 | 
						|
 | 
						|
#include "BLI_blenlib.h"
 | 
						|
#include "BLI_math.h"
 | 
						|
 | 
						|
#include "BKE_constraint.h"
 | 
						|
#include "BKE_armature.h"
 | 
						|
#include "BKE_context.h"
 | 
						|
 | 
						|
#include "ED_armature.h"
 | 
						|
#include "ED_util.h"
 | 
						|
 | 
						|
#include "BIF_retarget.h"
 | 
						|
 | 
						|
#include "armature_intern.h"
 | 
						|
 | 
						|
/************ RIG RETARGET DATA STRUCTURES ***************/
 | 
						|
 | 
						|
typedef struct MemoNode {
 | 
						|
	float weight;
 | 
						|
	int next;
 | 
						|
} MemoNode;
 | 
						|
 | 
						|
typedef struct RetargetParam {
 | 
						|
	RigGraph    *rigg;
 | 
						|
	RigArc      *iarc;
 | 
						|
	RigNode     *inode_start;
 | 
						|
	bContext    *context;
 | 
						|
} RetargetParam;
 | 
						|
 | 
						|
typedef enum  {
 | 
						|
	RETARGET_LENGTH,
 | 
						|
	RETARGET_AGGRESSIVE
 | 
						|
} RetargetMode; 
 | 
						|
 | 
						|
typedef enum {
 | 
						|
	METHOD_BRUTE_FORCE = 0,
 | 
						|
	METHOD_MEMOIZE = 1
 | 
						|
} RetargetMethod;
 | 
						|
 | 
						|
typedef enum {
 | 
						|
	ARC_FREE = 0,
 | 
						|
	ARC_TAKEN = 1,
 | 
						|
	ARC_USED = 2
 | 
						|
} ArcUsageFlags;
 | 
						|
 | 
						|
static RigGraph *GLOBAL_RIGG = NULL;
 | 
						|
 | 
						|
/*******************************************************************************************************/
 | 
						|
 | 
						|
void exec_retargetArctoArc(TaskPool *pool, void *taskdata, int threadid);
 | 
						|
 | 
						|
static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second);
 | 
						|
float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]);
 | 
						|
 | 
						|
/* two levels */
 | 
						|
#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX) 
 | 
						|
 | 
						|
/*********************************** EDITBONE UTILS ****************************************************/
 | 
						|
 | 
						|
static int countEditBoneChildren(ListBase *list, EditBone *parent)
 | 
						|
{
 | 
						|
	EditBone *ebone;
 | 
						|
	int count = 0;
 | 
						|
	
 | 
						|
	for (ebone = list->first; ebone; ebone = ebone->next) {
 | 
						|
		if (ebone->parent == parent) {
 | 
						|
			count++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	return count;
 | 
						|
}
 | 
						|
 | 
						|
static EditBone *nextEditBoneChild(ListBase *list, EditBone *parent, int n)
 | 
						|
{
 | 
						|
	EditBone *ebone;
 | 
						|
	
 | 
						|
	for (ebone = list->first; ebone; ebone = ebone->next) {
 | 
						|
		if (ebone->parent == parent) {
 | 
						|
			if (n == 0) {
 | 
						|
				return ebone;
 | 
						|
			}
 | 
						|
			n--;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3])
 | 
						|
{
 | 
						|
	float mat[3][3], nor[3];
 | 
						|
 | 
						|
	sub_v3_v3v3(nor, bone->tail, bone->head);
 | 
						|
	
 | 
						|
	vec_roll_to_mat3(nor, roll, mat);
 | 
						|
	copy_v3_v3(up_axis, mat[2]);
 | 
						|
}
 | 
						|
 | 
						|
static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3])
 | 
						|
{
 | 
						|
	float nor[3], new_up_axis[3], x_axis[3], z_axis[3];
 | 
						|
	
 | 
						|
	copy_v3_v3(new_up_axis, old_up_axis);
 | 
						|
	mul_qt_v3(qrot, new_up_axis);
 | 
						|
	
 | 
						|
	sub_v3_v3v3(nor, bone->tail, bone->head);
 | 
						|
	
 | 
						|
	cross_v3_v3v3(x_axis, nor, aligned_axis);
 | 
						|
	cross_v3_v3v3(z_axis, x_axis, nor);
 | 
						|
	
 | 
						|
	normalize_v3(new_up_axis);
 | 
						|
	normalize_v3(x_axis);
 | 
						|
	normalize_v3(z_axis);
 | 
						|
	
 | 
						|
	if (dot_v3v3(new_up_axis, x_axis) < 0) {
 | 
						|
		negate_v3(x_axis);
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (dot_v3v3(new_up_axis, z_axis) < 0) {
 | 
						|
		negate_v3(z_axis);
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) {
 | 
						|
		rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */
 | 
						|
		return ED_rollBoneToVector(bone, x_axis, false);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */
 | 
						|
		return ED_rollBoneToVector(bone, z_axis, false);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3])
 | 
						|
{
 | 
						|
	if (previous == NULL) {
 | 
						|
		/* default to up_axis if no previous */
 | 
						|
		return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		float new_up_axis[3];
 | 
						|
		float vec_first[3], vec_second[3], normal[3];
 | 
						|
		
 | 
						|
		if (previous->bone) {
 | 
						|
			sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head);
 | 
						|
		}
 | 
						|
		else if (previous->prev->bone) {
 | 
						|
			sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			/* default to up_axis if first bone in the chain is an offset */
 | 
						|
			return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
 | 
						|
		}
 | 
						|
		
 | 
						|
		sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head);
 | 
						|
	
 | 
						|
		normalize_v3(vec_first);
 | 
						|
		normalize_v3(vec_second);
 | 
						|
		
 | 
						|
		cross_v3_v3v3(normal, vec_first, vec_second);
 | 
						|
		normalize_v3(normal);
 | 
						|
		
 | 
						|
		axis_angle_to_quat(qroll, vec_second, edge->up_angle);
 | 
						|
		
 | 
						|
		mul_qt_v3(qroll, normal);
 | 
						|
			
 | 
						|
		copy_v3_v3(new_up_axis, edge->up_axis);
 | 
						|
		mul_qt_v3(qrot, new_up_axis);
 | 
						|
		
 | 
						|
		normalize_v3(new_up_axis);
 | 
						|
		
 | 
						|
		/* real qroll between normal and up_axis */
 | 
						|
		rotation_between_vecs_to_quat(qroll, new_up_axis, normal);
 | 
						|
 | 
						|
		return ED_rollBoneToVector(edge->bone, normal, false);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4])
 | 
						|
{
 | 
						|
	float new_up_axis[3];
 | 
						|
	
 | 
						|
	copy_v3_v3(new_up_axis, old_up_axis);
 | 
						|
	mul_qt_v3(qrot, new_up_axis);
 | 
						|
	
 | 
						|
	return ED_rollBoneToVector(bone, new_up_axis, false);
 | 
						|
}
 | 
						|
 | 
						|
/************************************ DESTRUCTORS ******************************************************/
 | 
						|
 | 
						|
static void RIG_freeRigArc(BArc *arc)
 | 
						|
{
 | 
						|
	BLI_freelistN(&((RigArc *)arc)->edges);
 | 
						|
}
 | 
						|
 | 
						|
void RIG_freeRigGraph(BGraph *rg)
 | 
						|
{
 | 
						|
	RigGraph *rigg = (RigGraph *)rg;
 | 
						|
	BNode *node;
 | 
						|
	BArc *arc;
 | 
						|
	
 | 
						|
	BLI_task_pool_free(rigg->task_pool);
 | 
						|
	BLI_task_scheduler_free(rigg->task_scheduler);
 | 
						|
	
 | 
						|
	if (rigg->link_mesh) {
 | 
						|
		REEB_freeGraph(rigg->link_mesh);
 | 
						|
	}
 | 
						|
	
 | 
						|
	for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
		RIG_freeRigArc(arc);
 | 
						|
	}
 | 
						|
	BLI_freelistN(&rg->arcs);
 | 
						|
	
 | 
						|
	for (node = rg->nodes.first; node; node = node->next) {
 | 
						|
		BLI_freeNode(rg, (BNode *)node);
 | 
						|
	}
 | 
						|
	BLI_freelistN(&rg->nodes);
 | 
						|
	
 | 
						|
	BLI_freelistN(&rigg->controls);
 | 
						|
 | 
						|
	BLI_ghash_free(rigg->bones_map, NULL, NULL);
 | 
						|
	BLI_ghash_free(rigg->controls_map, NULL, NULL);
 | 
						|
	
 | 
						|
	if (rigg->flag & RIG_FREE_BONELIST) {
 | 
						|
		BLI_freelistN(rigg->editbones);
 | 
						|
		MEM_freeN(rigg->editbones);
 | 
						|
	}
 | 
						|
	
 | 
						|
	MEM_freeN(rg);
 | 
						|
}
 | 
						|
 | 
						|
/************************************* ALLOCATORS ******************************************************/
 | 
						|
 | 
						|
static RigGraph *newRigGraph(void)
 | 
						|
{
 | 
						|
	RigGraph *rg;
 | 
						|
	int totthread;
 | 
						|
	
 | 
						|
	rg = MEM_callocN(sizeof(RigGraph), "rig graph");
 | 
						|
	
 | 
						|
	rg->head = NULL;
 | 
						|
	
 | 
						|
	rg->bones_map = BLI_ghash_str_new("newRigGraph bones gh");
 | 
						|
	rg->controls_map = BLI_ghash_str_new("newRigGraph cont gh");
 | 
						|
	
 | 
						|
	rg->free_arc = RIG_freeRigArc;
 | 
						|
	rg->free_node = NULL;
 | 
						|
	
 | 
						|
#ifdef USE_THREADS
 | 
						|
	totthread = TASK_SCHEDULER_AUTO_THREADS;
 | 
						|
#else
 | 
						|
	totthread = TASK_SCHEDULER_SINGLE_THREAD;
 | 
						|
#endif
 | 
						|
 | 
						|
	rg->task_scheduler = BLI_task_scheduler_create(totthread);
 | 
						|
	rg->task_pool = BLI_task_pool_create(rg->task_scheduler, NULL);
 | 
						|
 | 
						|
	return rg;
 | 
						|
}
 | 
						|
 | 
						|
static RigArc *newRigArc(RigGraph *rg)
 | 
						|
{
 | 
						|
	RigArc *arc;
 | 
						|
	
 | 
						|
	arc = MEM_callocN(sizeof(RigArc), "rig arc");
 | 
						|
	arc->count = 0;
 | 
						|
	BLI_addtail(&rg->arcs, arc);
 | 
						|
	
 | 
						|
	return arc;
 | 
						|
}
 | 
						|
 | 
						|
static RigControl *newRigControl(RigGraph *rg)
 | 
						|
{
 | 
						|
	RigControl *ctrl;
 | 
						|
	
 | 
						|
	ctrl = MEM_callocN(sizeof(RigControl), "rig control");
 | 
						|
	
 | 
						|
	BLI_addtail(&rg->controls, ctrl);
 | 
						|
	
 | 
						|
	return ctrl;
 | 
						|
}
 | 
						|
 | 
						|
static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3])
 | 
						|
{
 | 
						|
	RigNode *node;
 | 
						|
	node = MEM_callocN(sizeof(RigNode), "rig node");
 | 
						|
	BLI_addtail(&rg->nodes, node);
 | 
						|
 | 
						|
	copy_v3_v3(node->p, p);
 | 
						|
	node->degree = 1;
 | 
						|
	node->arcs = NULL;
 | 
						|
	
 | 
						|
	arc->head = node;
 | 
						|
	
 | 
						|
	return node;
 | 
						|
}
 | 
						|
 | 
						|
static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node)
 | 
						|
{
 | 
						|
	node->degree++;
 | 
						|
 | 
						|
	arc->head = node;
 | 
						|
}
 | 
						|
 | 
						|
static RigNode *newRigNode(RigGraph *rg, float p[3])
 | 
						|
{
 | 
						|
	RigNode *node;
 | 
						|
	node = MEM_callocN(sizeof(RigNode), "rig node");
 | 
						|
	BLI_addtail(&rg->nodes, node);
 | 
						|
 | 
						|
	copy_v3_v3(node->p, p);
 | 
						|
	node->degree = 0;
 | 
						|
	node->arcs = NULL;
 | 
						|
	
 | 
						|
	return node;
 | 
						|
}
 | 
						|
 | 
						|
static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3])
 | 
						|
{
 | 
						|
	RigNode *node = newRigNode(rg, p);
 | 
						|
	
 | 
						|
	node->degree = 1;
 | 
						|
	arc->tail = node;
 | 
						|
 | 
						|
	return node;
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge)
 | 
						|
{
 | 
						|
	BLI_addtail(&arc->edges, edge);
 | 
						|
 | 
						|
	if (edge->prev == NULL) {
 | 
						|
		copy_v3_v3(edge->head, arc->head->p);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		RigEdge *last_edge = edge->prev;
 | 
						|
		copy_v3_v3(edge->head, last_edge->tail);
 | 
						|
		RIG_calculateEdgeAngles(last_edge, edge);
 | 
						|
	}
 | 
						|
	
 | 
						|
	edge->length = len_v3v3(edge->head, edge->tail);
 | 
						|
	
 | 
						|
	arc->length += edge->length;
 | 
						|
	
 | 
						|
	arc->count += 1;
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone)
 | 
						|
{
 | 
						|
	RigEdge *edge;
 | 
						|
 | 
						|
	edge = MEM_callocN(sizeof(RigEdge), "rig edge");
 | 
						|
 | 
						|
	copy_v3_v3(edge->tail, tail);
 | 
						|
	edge->bone = bone;
 | 
						|
	
 | 
						|
	if (bone) {
 | 
						|
		getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis);
 | 
						|
	}
 | 
						|
	
 | 
						|
	RIG_appendEdgeToArc(arc, edge);
 | 
						|
}
 | 
						|
/************************************** CLONING TEMPLATES **********************************************/
 | 
						|
 | 
						|
static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string)
 | 
						|
{
 | 
						|
	int i, j;
 | 
						|
	
 | 
						|
	for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) {
 | 
						|
		if (template_name[i] == '&') {
 | 
						|
			if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') {
 | 
						|
				j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME);
 | 
						|
				i++;
 | 
						|
			}
 | 
						|
			else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') {
 | 
						|
				j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME);
 | 
						|
				i++;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				name[j] = template_name[i];
 | 
						|
				j++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			name[j] = template_name[i];
 | 
						|
			j++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	name[j] = '\0';
 | 
						|
	
 | 
						|
	unique_editbone_name(editbones, name, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string)
 | 
						|
{
 | 
						|
	RigControl *ctrl;
 | 
						|
	char name[MAXBONENAME];
 | 
						|
	
 | 
						|
	ctrl = newRigControl(rg);
 | 
						|
	
 | 
						|
	copy_v3_v3(ctrl->head, src_ctrl->head);
 | 
						|
	copy_v3_v3(ctrl->tail, src_ctrl->tail);
 | 
						|
	copy_v3_v3(ctrl->up_axis, src_ctrl->up_axis);
 | 
						|
	copy_v3_v3(ctrl->offset, src_ctrl->offset);
 | 
						|
	
 | 
						|
	ctrl->tail_mode = src_ctrl->tail_mode;
 | 
						|
	ctrl->flag = src_ctrl->flag;
 | 
						|
 | 
						|
	renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string);
 | 
						|
	ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob);
 | 
						|
	ctrl->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
 | 
						|
	BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone);
 | 
						|
	
 | 
						|
	ctrl->link = src_ctrl->link;
 | 
						|
	ctrl->link_tail = src_ctrl->link_tail;
 | 
						|
	
 | 
						|
	return ctrl;
 | 
						|
}
 | 
						|
 | 
						|
static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string)
 | 
						|
{
 | 
						|
	RigEdge *src_edge;
 | 
						|
	RigArc  *arc;
 | 
						|
	
 | 
						|
	arc = newRigArc(rg);
 | 
						|
	
 | 
						|
	arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head);
 | 
						|
	arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail);
 | 
						|
	
 | 
						|
	arc->head->degree++;
 | 
						|
	arc->tail->degree++;
 | 
						|
	
 | 
						|
	arc->length = src_arc->length;
 | 
						|
 | 
						|
	arc->count = src_arc->count;
 | 
						|
	
 | 
						|
	for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) {
 | 
						|
		RigEdge *edge;
 | 
						|
	
 | 
						|
		edge = MEM_callocN(sizeof(RigEdge), "rig edge");
 | 
						|
 | 
						|
		copy_v3_v3(edge->head, src_edge->head);
 | 
						|
		copy_v3_v3(edge->tail, src_edge->tail);
 | 
						|
		copy_v3_v3(edge->up_axis, src_edge->up_axis);
 | 
						|
		
 | 
						|
		edge->length = src_edge->length;
 | 
						|
		edge->angle = src_edge->angle;
 | 
						|
		edge->up_angle = src_edge->up_angle;
 | 
						|
		
 | 
						|
		if (src_edge->bone != NULL) {
 | 
						|
			char name[MAXBONENAME];
 | 
						|
			renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string);
 | 
						|
			edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob);
 | 
						|
			edge->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
 | 
						|
			BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone);
 | 
						|
		}
 | 
						|
 | 
						|
		BLI_addtail(&arc->edges, edge);
 | 
						|
	}
 | 
						|
	
 | 
						|
	return arc;
 | 
						|
}
 | 
						|
 | 
						|
static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string)
 | 
						|
{
 | 
						|
	GHash   *ptr_hash;
 | 
						|
	RigNode *node;
 | 
						|
	RigArc  *arc;
 | 
						|
	RigControl *ctrl;
 | 
						|
	RigGraph *rg;
 | 
						|
	
 | 
						|
	ptr_hash = BLI_ghash_ptr_new("cloneRigGraph gh");
 | 
						|
 | 
						|
	rg = newRigGraph();
 | 
						|
	
 | 
						|
	rg->ob = ob;
 | 
						|
	rg->editbones = editbones;
 | 
						|
	
 | 
						|
	preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */
 | 
						|
	preEditBoneDuplicate(src->editbones); /* prime bones for duplication */
 | 
						|
	
 | 
						|
	/* Clone nodes */
 | 
						|
	for (node = src->nodes.first; node; node = node->next) {
 | 
						|
		RigNode *cloned_node = newRigNode(rg, node->p);
 | 
						|
		BLI_ghash_insert(ptr_hash, node, cloned_node);
 | 
						|
	}
 | 
						|
	
 | 
						|
	rg->head = BLI_ghash_lookup(ptr_hash, src->head);
 | 
						|
	
 | 
						|
	/* Clone arcs */
 | 
						|
	for (arc = src->arcs.first; arc; arc = arc->next) {
 | 
						|
		cloneArc(rg, src, arc, ptr_hash, side_string, num_string);
 | 
						|
	}
 | 
						|
	
 | 
						|
	/* Clone controls */
 | 
						|
	for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) {
 | 
						|
		cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string);
 | 
						|
	}
 | 
						|
	
 | 
						|
	/* Relink bones properly */
 | 
						|
	for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
		RigEdge *edge;
 | 
						|
		
 | 
						|
		for (edge = arc->edges.first; edge; edge = edge->next) {
 | 
						|
			if (edge->bone != NULL) {
 | 
						|
				EditBone *bone;
 | 
						|
				
 | 
						|
				updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob);
 | 
						|
 | 
						|
				if (edge->bone->parent) {
 | 
						|
					bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent);
 | 
						|
		
 | 
						|
					if (bone != NULL) {
 | 
						|
						edge->bone->parent = bone;
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						/* disconnect since parent isn't cloned
 | 
						|
						 * this will only happen when cloning from selected bones 
 | 
						|
						 * */
 | 
						|
						edge->bone->flag &= ~BONE_CONNECTED;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
 | 
						|
		EditBone *bone;
 | 
						|
		
 | 
						|
		updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob);
 | 
						|
 | 
						|
		if (ctrl->bone->parent) {
 | 
						|
			bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent);
 | 
						|
			
 | 
						|
			if (bone != NULL) {
 | 
						|
				ctrl->bone->parent = bone;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				/* disconnect since parent isn't cloned
 | 
						|
				 * this will only happen when cloning from selected bones 
 | 
						|
				 * */
 | 
						|
				ctrl->bone->flag &= ~BONE_CONNECTED;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link);
 | 
						|
		ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail);
 | 
						|
	}
 | 
						|
	
 | 
						|
	BLI_ghash_free(ptr_hash, NULL, NULL);
 | 
						|
	
 | 
						|
	return rg;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*******************************************************************************************************/
 | 
						|
 | 
						|
static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second)
 | 
						|
{
 | 
						|
	float vec_first[3], vec_second[3];
 | 
						|
	
 | 
						|
	sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head); 
 | 
						|
	sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head);
 | 
						|
 | 
						|
	normalize_v3(vec_first);
 | 
						|
	normalize_v3(vec_second);
 | 
						|
	
 | 
						|
	edge_first->angle = angle_normalized_v3v3(vec_first, vec_second);
 | 
						|
	
 | 
						|
	if (edge_second->bone != NULL) {
 | 
						|
		float normal[3];
 | 
						|
 | 
						|
		cross_v3_v3v3(normal, vec_first, vec_second);
 | 
						|
		normalize_v3(normal);
 | 
						|
 | 
						|
		edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/************************************ CONTROL BONES ****************************************************/
 | 
						|
 | 
						|
static void RIG_addControlBone(RigGraph *rg, EditBone *bone)
 | 
						|
{
 | 
						|
	RigControl *ctrl = newRigControl(rg);
 | 
						|
	ctrl->bone = bone;
 | 
						|
	copy_v3_v3(ctrl->head, bone->head);
 | 
						|
	copy_v3_v3(ctrl->tail, bone->tail);
 | 
						|
	getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis);
 | 
						|
	ctrl->tail_mode = TL_NONE;
 | 
						|
	
 | 
						|
	BLI_ghash_insert(rg->controls_map, bone->name, ctrl);
 | 
						|
}
 | 
						|
 | 
						|
static int RIG_parentControl(RigControl *ctrl, EditBone *link)
 | 
						|
{
 | 
						|
	if (link) {
 | 
						|
		float offset[3];
 | 
						|
		int flag = 0;
 | 
						|
		
 | 
						|
		sub_v3_v3v3(offset, ctrl->bone->head, link->head);
 | 
						|
 | 
						|
		/* if root matches, check for direction too */
 | 
						|
		if (dot_v3v3(offset, offset) < 0.0001f) {
 | 
						|
			float vbone[3], vparent[3];
 | 
						|
			
 | 
						|
			flag |= RIG_CTRL_FIT_ROOT;
 | 
						|
			
 | 
						|
			sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head);
 | 
						|
			sub_v3_v3v3(vparent, link->tail, link->head);
 | 
						|
			
 | 
						|
			/* test for opposite direction */
 | 
						|
			if (dot_v3v3(vbone, vparent) > 0) {
 | 
						|
				float nor[3];
 | 
						|
				float len;
 | 
						|
				
 | 
						|
				cross_v3_v3v3(nor, vbone, vparent);
 | 
						|
				
 | 
						|
				len = dot_v3v3(nor, nor);
 | 
						|
				if (len < 0.0001f) {
 | 
						|
					flag |= RIG_CTRL_FIT_BONE;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		/* Bail out if old one is automatically better */
 | 
						|
		if (flag < ctrl->flag) {
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		
 | 
						|
		/* if there's already a link
 | 
						|
		 *  overwrite only if new link is higher in the chain */
 | 
						|
		if (ctrl->link && flag == ctrl->flag) {
 | 
						|
			EditBone *bone = NULL;
 | 
						|
			
 | 
						|
			for (bone = ctrl->link; bone; bone = bone->parent) {
 | 
						|
				/* if link is in the chain, break and use that one */
 | 
						|
				if (bone == link) {
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			
 | 
						|
			/* not in chain, don't update link */
 | 
						|
			if (bone == NULL) {
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		
 | 
						|
		ctrl->link = link;
 | 
						|
		ctrl->flag = flag;
 | 
						|
		
 | 
						|
		copy_v3_v3(ctrl->offset, offset);
 | 
						|
		
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
	
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_reconnectControlBones(RigGraph *rg)
 | 
						|
{
 | 
						|
	RigControl *ctrl;
 | 
						|
	bool changed = true;
 | 
						|
	
 | 
						|
	/* first pass, link to deform bones */
 | 
						|
	for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
 | 
						|
		bPoseChannel *pchan;
 | 
						|
		bConstraint *con;
 | 
						|
		int found = 0;
 | 
						|
		
 | 
						|
		/* DO SOME MAGIC HERE */
 | 
						|
		for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 | 
						|
			for (con = pchan->constraints.first; con; con = con->next) {
 | 
						|
				bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
 | 
						|
				ListBase targets = {NULL, NULL};
 | 
						|
				bConstraintTarget *ct;
 | 
						|
				
 | 
						|
				/* constraint targets */
 | 
						|
				if (cti && cti->get_constraint_targets) {
 | 
						|
					int target_index;
 | 
						|
					
 | 
						|
					cti->get_constraint_targets(con, &targets);
 | 
						|
					
 | 
						|
					for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) {
 | 
						|
						if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) {
 | 
						|
							/* SET bone link to bone corresponding to pchan */
 | 
						|
							EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name);
 | 
						|
							
 | 
						|
							/* Making sure bone is in this armature */
 | 
						|
							if (link != NULL) {
 | 
						|
								/* for pole targets, link to parent bone instead, if possible */
 | 
						|
								if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) {
 | 
						|
									if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) {
 | 
						|
										link = link->parent;
 | 
						|
									}
 | 
						|
								}
 | 
						|
								
 | 
						|
								found = RIG_parentControl(ctrl, link);
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
					
 | 
						|
					if (cti->flush_constraint_targets)
 | 
						|
						cti->flush_constraint_targets(con, &targets, 0);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* if not found yet, check parent */
 | 
						|
		if (found == 0) {
 | 
						|
			if (ctrl->bone->parent) {
 | 
						|
				/* make sure parent is a deforming bone
 | 
						|
				 * NULL if not
 | 
						|
				 *  */
 | 
						|
				EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name);
 | 
						|
				
 | 
						|
				found = RIG_parentControl(ctrl, link);
 | 
						|
			}
 | 
						|
			
 | 
						|
			/* check if bone is not superposed on another one */
 | 
						|
			{
 | 
						|
				RigArc *arc;
 | 
						|
				RigArc *best_arc = NULL;
 | 
						|
				EditBone *link = NULL;
 | 
						|
				
 | 
						|
				for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
					RigEdge *edge;
 | 
						|
					for (edge = arc->edges.first; edge; edge = edge->next) {
 | 
						|
						if (edge->bone) {
 | 
						|
							int fit = 0;
 | 
						|
							
 | 
						|
							fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001f;
 | 
						|
							fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001f;
 | 
						|
							
 | 
						|
							if (fit) {
 | 
						|
								/* pick the bone on the arc with the lowest symmetry level
 | 
						|
								 * means you connect control to the trunk of the skeleton */
 | 
						|
								if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
 | 
						|
									best_arc = arc;
 | 
						|
									link = edge->bone;
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
				
 | 
						|
				found = RIG_parentControl(ctrl, link);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		/* if not found yet, check child */
 | 
						|
		if (found == 0) {
 | 
						|
			RigArc *arc;
 | 
						|
			RigArc *best_arc = NULL;
 | 
						|
			EditBone *link = NULL;
 | 
						|
			
 | 
						|
			for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
				RigEdge *edge;
 | 
						|
				for (edge = arc->edges.first; edge; edge = edge->next) {
 | 
						|
					if (edge->bone && edge->bone->parent == ctrl->bone) {
 | 
						|
						/* pick the bone on the arc with the lowest symmetry level
 | 
						|
						 * means you connect control to the trunk of the skeleton */
 | 
						|
						if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
 | 
						|
							best_arc = arc;
 | 
						|
							link = edge->bone;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			
 | 
						|
			found = RIG_parentControl(ctrl, link);
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	
 | 
						|
	
 | 
						|
	/* second pass, make chains in control bones */
 | 
						|
	while (changed) {
 | 
						|
		changed = false;
 | 
						|
		
 | 
						|
		for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
 | 
						|
			/* if control is not linked yet */
 | 
						|
			if (ctrl->link == NULL) {
 | 
						|
				bPoseChannel *pchan;
 | 
						|
				bConstraint *con;
 | 
						|
				RigControl *ctrl_parent = NULL;
 | 
						|
				RigControl *ctrl_child;
 | 
						|
				int found = 0;
 | 
						|
 | 
						|
				if (ctrl->bone->parent) {
 | 
						|
					ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name);
 | 
						|
				}
 | 
						|
 | 
						|
				/* check constraints first */
 | 
						|
				
 | 
						|
				/* DO SOME MAGIC HERE */
 | 
						|
				for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 | 
						|
					for (con = pchan->constraints.first; con; con = con->next) {
 | 
						|
						bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
 | 
						|
						ListBase targets = {NULL, NULL};
 | 
						|
						bConstraintTarget *ct;
 | 
						|
						
 | 
						|
						/* constraint targets */
 | 
						|
						if (cti && cti->get_constraint_targets) {
 | 
						|
							cti->get_constraint_targets(con, &targets);
 | 
						|
							
 | 
						|
							for (ct = targets.first; ct; ct = ct->next) {
 | 
						|
								if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) {
 | 
						|
									/* SET bone link to ctrl corresponding to pchan */
 | 
						|
									RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name);
 | 
						|
 | 
						|
									/* if owner is a control bone, link with it */
 | 
						|
									if (link && link->link) {
 | 
						|
										RIG_parentControl(ctrl, link->bone);
 | 
						|
										found = 1;
 | 
						|
										break;
 | 
						|
									}
 | 
						|
								}
 | 
						|
							}
 | 
						|
							
 | 
						|
							if (cti->flush_constraint_targets)
 | 
						|
								cti->flush_constraint_targets(con, &targets, 0);
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if (found == 0) {
 | 
						|
					/* check if parent is already linked */
 | 
						|
					if (ctrl_parent && ctrl_parent->link) {
 | 
						|
						RIG_parentControl(ctrl, ctrl_parent->bone);
 | 
						|
						changed = true;
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						/* check childs */
 | 
						|
						for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
 | 
						|
							/* if a child is linked, link to that one */
 | 
						|
							if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) {
 | 
						|
								RIG_parentControl(ctrl, ctrl_child->bone);
 | 
						|
								changed = true;
 | 
						|
								break;
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	/* third pass, link control tails */
 | 
						|
	for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
 | 
						|
		/* fit bone already means full match, so skip those */
 | 
						|
		if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) {
 | 
						|
			GHashIterator ghi;
 | 
						|
			
 | 
						|
			/* look on deform bones first */
 | 
						|
			BLI_ghashIterator_init(&ghi, rg->bones_map);
 | 
						|
			
 | 
						|
			for (; !BLI_ghashIterator_done(&ghi); BLI_ghashIterator_step(&ghi)) {
 | 
						|
				EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi);
 | 
						|
				
 | 
						|
				/* don't link with parent */
 | 
						|
				if (bone->parent != ctrl->bone) {
 | 
						|
					if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01f) {
 | 
						|
						ctrl->tail_mode = TL_HEAD;
 | 
						|
						ctrl->link_tail = bone;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
					else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01f) {
 | 
						|
						ctrl->tail_mode = TL_TAIL;
 | 
						|
						ctrl->link_tail = bone;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			
 | 
						|
			/* if we haven't found one yet, look in control bones */
 | 
						|
			if (ctrl->tail_mode == TL_NONE) {
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************************************/
 | 
						|
 | 
						|
static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2)
 | 
						|
{
 | 
						|
	RigEdge *edge, *next_edge;
 | 
						|
	
 | 
						|
	/* ignore cases where joint is at start or end */
 | 
						|
	if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	
 | 
						|
	/* swap arcs to make sure arc1 is before arc2 */
 | 
						|
	if (joined_arc1->head == joined_arc2->tail) {
 | 
						|
		RigArc *tmp = joined_arc1;
 | 
						|
		joined_arc1 = joined_arc2;
 | 
						|
		joined_arc2 = tmp;
 | 
						|
	}
 | 
						|
	
 | 
						|
	for (edge = joined_arc2->edges.first; edge; edge = next_edge) {
 | 
						|
		next_edge = edge->next;
 | 
						|
		
 | 
						|
		RIG_appendEdgeToArc(joined_arc1, edge);
 | 
						|
	}
 | 
						|
	
 | 
						|
	joined_arc1->tail = joined_arc2->tail;
 | 
						|
	
 | 
						|
	BLI_listbase_clear(&joined_arc2->edges);
 | 
						|
	
 | 
						|
	BLI_removeArc((BGraph *)rg, (BArc *)joined_arc2);
 | 
						|
	
 | 
						|
	BLI_removeNode((BGraph *)rg, (BNode *)node);
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_removeNormalNodes(RigGraph *rg)
 | 
						|
{
 | 
						|
	RigNode *node, *next_node;
 | 
						|
	
 | 
						|
	for (node = rg->nodes.first; node; node = next_node) {
 | 
						|
		next_node = node->next;
 | 
						|
		
 | 
						|
		if (node->degree == 2) {
 | 
						|
			RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL;
 | 
						|
			
 | 
						|
			for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
				if (arc->head == node || arc->tail == node) {
 | 
						|
					if (joined_arc1 == NULL) {
 | 
						|
						joined_arc1 = arc;
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						joined_arc2 = arc;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			
 | 
						|
			RIG_joinArcs(rg, node, joined_arc1, joined_arc2);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_removeUneededOffsets(RigGraph *rg)
 | 
						|
{
 | 
						|
	RigArc *arc;
 | 
						|
	
 | 
						|
	for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
		RigEdge *first_edge, *last_edge;
 | 
						|
		
 | 
						|
		first_edge = arc->edges.first;
 | 
						|
		last_edge = arc->edges.last;
 | 
						|
		
 | 
						|
		if (first_edge->bone == NULL) {
 | 
						|
			if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001f) {
 | 
						|
				BLI_remlink(&arc->edges, first_edge);
 | 
						|
				MEM_freeN(first_edge);
 | 
						|
			}
 | 
						|
			else if (arc->head->degree == 1) {
 | 
						|
				RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001f);
 | 
						|
				
 | 
						|
				if (new_node) {
 | 
						|
					BLI_remlink(&arc->edges, first_edge);
 | 
						|
					MEM_freeN(first_edge);
 | 
						|
					BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					RigEdge *next_edge = first_edge->next;
 | 
						|
	
 | 
						|
					if (next_edge) {
 | 
						|
						BLI_remlink(&arc->edges, first_edge);
 | 
						|
						MEM_freeN(first_edge);
 | 
						|
						
 | 
						|
						copy_v3_v3(arc->head->p, next_edge->head);
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				/* check if all arc connected start with a null edge */
 | 
						|
				RigArc *other_arc;
 | 
						|
				for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
 | 
						|
					if (other_arc != arc) {
 | 
						|
						RigEdge *test_edge;
 | 
						|
						if (other_arc->head == arc->head) {
 | 
						|
							test_edge = other_arc->edges.first;
 | 
						|
							
 | 
						|
							if (test_edge->bone != NULL) {
 | 
						|
								break;
 | 
						|
							}
 | 
						|
						}
 | 
						|
						else if (other_arc->tail == arc->head) {
 | 
						|
							test_edge = other_arc->edges.last;
 | 
						|
							
 | 
						|
							if (test_edge->bone != NULL) {
 | 
						|
								break;
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
				
 | 
						|
				if (other_arc == NULL) {
 | 
						|
					RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001);
 | 
						|
					
 | 
						|
					if (new_node) {
 | 
						|
						/* remove null edge in other arcs too */
 | 
						|
						for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
 | 
						|
							if (other_arc != arc) {
 | 
						|
								RigEdge *test_edge;
 | 
						|
								if (other_arc->head == arc->head) {
 | 
						|
									BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->head);
 | 
						|
									test_edge = other_arc->edges.first;
 | 
						|
									BLI_remlink(&other_arc->edges, test_edge);
 | 
						|
									MEM_freeN(test_edge);
 | 
						|
								}
 | 
						|
								else if (other_arc->tail == arc->head) {
 | 
						|
									BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->tail);
 | 
						|
									test_edge = other_arc->edges.last;
 | 
						|
									BLI_remlink(&other_arc->edges, test_edge);
 | 
						|
									MEM_freeN(test_edge);
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
						
 | 
						|
						BLI_remlink(&arc->edges, first_edge);
 | 
						|
						MEM_freeN(first_edge);
 | 
						|
						BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						RigEdge *next_edge = first_edge->next;
 | 
						|
		
 | 
						|
						if (next_edge) {
 | 
						|
							BLI_remlink(&arc->edges, first_edge);
 | 
						|
							MEM_freeN(first_edge);
 | 
						|
							
 | 
						|
							copy_v3_v3(arc->head->p, next_edge->head);
 | 
						|
							
 | 
						|
							/* remove null edge in other arcs too */
 | 
						|
							for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
 | 
						|
								if (other_arc != arc) {
 | 
						|
									RigEdge *test_edge;
 | 
						|
									if (other_arc->head == arc->head) {
 | 
						|
										test_edge = other_arc->edges.first;
 | 
						|
										BLI_remlink(&other_arc->edges, test_edge);
 | 
						|
										MEM_freeN(test_edge);
 | 
						|
									}
 | 
						|
									else if (other_arc->tail == arc->head) {
 | 
						|
										test_edge = other_arc->edges.last;
 | 
						|
										BLI_remlink(&other_arc->edges, test_edge);
 | 
						|
										MEM_freeN(test_edge);
 | 
						|
									}
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (last_edge->bone == NULL) {
 | 
						|
			if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001f) {
 | 
						|
				BLI_remlink(&arc->edges, last_edge);
 | 
						|
				MEM_freeN(last_edge);
 | 
						|
			}
 | 
						|
			else if (arc->tail->degree == 1) {
 | 
						|
				RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, last_edge->head, 0.001f);
 | 
						|
				
 | 
						|
				if (new_node) {
 | 
						|
					RigEdge *previous_edge = last_edge->prev;
 | 
						|
					
 | 
						|
					BLI_remlink(&arc->edges, last_edge);
 | 
						|
					MEM_freeN(last_edge);
 | 
						|
					BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->tail);
 | 
						|
					
 | 
						|
					/* set previous angle to 0, since there's no following edges */
 | 
						|
					if (previous_edge) {
 | 
						|
						previous_edge->angle = 0;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					RigEdge *previous_edge = last_edge->prev;
 | 
						|
	
 | 
						|
					if (previous_edge) {
 | 
						|
						BLI_remlink(&arc->edges, last_edge);
 | 
						|
						MEM_freeN(last_edge);
 | 
						|
						
 | 
						|
						copy_v3_v3(arc->tail->p, previous_edge->tail);
 | 
						|
						previous_edge->angle = 0;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, bool selected)
 | 
						|
{
 | 
						|
	EditBone *bone, *last_bone = root_bone;
 | 
						|
	RigArc *arc = NULL;
 | 
						|
	int contain_head = 0;
 | 
						|
	
 | 
						|
	for (bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) {
 | 
						|
		int nb_children;
 | 
						|
		
 | 
						|
		if (selected == 0 || (bone->flag & BONE_SELECTED)) {
 | 
						|
			if ((bone->flag & BONE_NO_DEFORM) == 0) {
 | 
						|
				BLI_ghash_insert(rg->bones_map, bone->name, bone);
 | 
						|
			
 | 
						|
				if (arc == NULL) {
 | 
						|
					arc = newRigArc(rg);
 | 
						|
					
 | 
						|
					if (starting_node == NULL) {
 | 
						|
						starting_node = newRigNodeHead(rg, arc, root_bone->head);
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						addRigNodeHead(rg, arc, starting_node);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				
 | 
						|
				if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) {
 | 
						|
					RIG_addEdgeToArc(arc, bone->head, NULL);
 | 
						|
				}
 | 
						|
				
 | 
						|
				RIG_addEdgeToArc(arc, bone->tail, bone);
 | 
						|
				
 | 
						|
				last_bone = bone;
 | 
						|
				
 | 
						|
				if (strcmp(bone->name, "head") == 0) {
 | 
						|
					contain_head = 1;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) { /* ignore locked bones */
 | 
						|
				RIG_addControlBone(rg, bone);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		nb_children = countEditBoneChildren(list, bone);
 | 
						|
		if (nb_children > 1) {
 | 
						|
			RigNode *end_node = NULL;
 | 
						|
			int i;
 | 
						|
			
 | 
						|
			if (arc != NULL) {
 | 
						|
				end_node = newRigNodeTail(rg, arc, bone->tail);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				end_node = newRigNode(rg, bone->tail);
 | 
						|
			}
 | 
						|
 | 
						|
			for (i = 0; i < nb_children; i++) {
 | 
						|
				root_bone = nextEditBoneChild(list, bone, i);
 | 
						|
				RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected);
 | 
						|
			}
 | 
						|
			
 | 
						|
			/* arc ends here, break */
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	/* If the loop exited without forking */
 | 
						|
	if (arc != NULL && bone == NULL) {
 | 
						|
		newRigNodeTail(rg, arc, last_bone->tail);
 | 
						|
	}
 | 
						|
 | 
						|
	if (contain_head) {
 | 
						|
		rg->head = arc->tail;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************************************/
 | 
						|
static void RIG_findHead(RigGraph *rg)
 | 
						|
{
 | 
						|
	if (rg->head == NULL) {
 | 
						|
		if (BLI_listbase_is_single(&rg->arcs)) {
 | 
						|
			RigArc *arc = rg->arcs.first;
 | 
						|
			
 | 
						|
			rg->head = (RigNode *)arc->head;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			RigArc *arc;
 | 
						|
			
 | 
						|
			for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
				RigEdge *edge = arc->edges.last;
 | 
						|
				
 | 
						|
				if (edge->bone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
 | 
						|
					rg->head = arc->tail;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (rg->head == NULL) {
 | 
						|
			rg->head = rg->nodes.first;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************************************/
 | 
						|
 | 
						|
static void RIG_printNode(RigNode *node, const char name[])
 | 
						|
{
 | 
						|
	printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]);
 | 
						|
	
 | 
						|
	if (node->symmetry_flag & SYM_TOPOLOGICAL) {
 | 
						|
		if (node->symmetry_flag & SYM_AXIAL)
 | 
						|
			printf("Symmetry AXIAL\n");
 | 
						|
		else if (node->symmetry_flag & SYM_RADIAL)
 | 
						|
			printf("Symmetry RADIAL\n");
 | 
						|
			
 | 
						|
		print_v3("symmetry axis", node->symmetry_axis);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void RIG_printArcBones(RigArc *arc)
 | 
						|
{
 | 
						|
	RigEdge *edge;
 | 
						|
 | 
						|
	for (edge = arc->edges.first; edge; edge = edge->next) {
 | 
						|
		if (edge->bone)
 | 
						|
			printf("%s ", edge->bone->name);
 | 
						|
		else
 | 
						|
			printf("---- ");
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_printCtrl(RigControl *ctrl, char *indent)
 | 
						|
{
 | 
						|
	char text[128];
 | 
						|
	
 | 
						|
	printf("%sBone: %s\n", indent, ctrl->bone->name);
 | 
						|
	printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!");
 | 
						|
	
 | 
						|
	BLI_snprintf(text, sizeof(text), "%soffset", indent);
 | 
						|
	print_v3(text, ctrl->offset);
 | 
						|
	
 | 
						|
	printf("%sFlag: %i\n", indent, ctrl->flag);
 | 
						|
}
 | 
						|
 | 
						|
static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs)
 | 
						|
{
 | 
						|
	RigControl *ctrl;
 | 
						|
	char indent[64];
 | 
						|
	char *s = indent;
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	for (i = 0; i < tabs; i++) {
 | 
						|
		s[0] = '\t';
 | 
						|
		s++;
 | 
						|
	}
 | 
						|
	s[0] = 0;
 | 
						|
	
 | 
						|
	for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
 | 
						|
		if (ctrl->link == bone) {
 | 
						|
			RIG_printCtrl(ctrl, indent);
 | 
						|
			RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void RIG_printArc(RigGraph *rg, RigArc *arc)
 | 
						|
{
 | 
						|
	RigEdge *edge;
 | 
						|
 | 
						|
	RIG_printNode((RigNode *)arc->head, "head");
 | 
						|
 | 
						|
	for (edge = arc->edges.first; edge; edge = edge->next) {
 | 
						|
		printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]);
 | 
						|
		printf("\t\tlength %f\n", edge->length);
 | 
						|
		printf("\t\tangle %f\n", edge->angle * (float)(180 / M_PI));
 | 
						|
		if (edge->bone) {
 | 
						|
			printf("\t\t%s\n", edge->bone->name);
 | 
						|
			RIG_printLinkedCtrl(rg, edge->bone, 3);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group);
 | 
						|
 | 
						|
	RIG_printNode((RigNode *)arc->tail, "tail");
 | 
						|
}
 | 
						|
 | 
						|
void RIG_printGraph(RigGraph *rg)
 | 
						|
{
 | 
						|
	RigArc *arc;
 | 
						|
 | 
						|
	printf("---- ARCS ----\n");
 | 
						|
	for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
		RIG_printArc(rg, arc);
 | 
						|
		printf("\n");
 | 
						|
	}
 | 
						|
 | 
						|
	if (rg->head) {
 | 
						|
		RIG_printNode(rg->head, "HEAD NODE:");
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		printf("HEAD NODE: NONE\n");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************************************/
 | 
						|
 | 
						|
RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm)
 | 
						|
{
 | 
						|
	Object *obedit = CTX_data_edit_object(C);
 | 
						|
	Scene *scene = CTX_data_scene(C);
 | 
						|
	EditBone *ebone;
 | 
						|
	RigGraph *rg;
 | 
						|
 | 
						|
	rg = newRigGraph();
 | 
						|
	
 | 
						|
	if (obedit == ob) {
 | 
						|
		rg->editbones = ((bArmature *)obedit->data)->edbo;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
 | 
						|
		make_boneList(rg->editbones, &arm->bonebase, NULL, NULL);
 | 
						|
		rg->flag |= RIG_FREE_BONELIST;
 | 
						|
	}
 | 
						|
	
 | 
						|
	rg->ob = ob;
 | 
						|
 | 
						|
	/* Do the rotations */
 | 
						|
	for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
 | 
						|
		if (ebone->parent == NULL) {
 | 
						|
			RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	BLI_removeDoubleNodes((BGraph *)rg, 0.001);
 | 
						|
	
 | 
						|
	RIG_removeNormalNodes(rg);
 | 
						|
	
 | 
						|
	RIG_removeUneededOffsets(rg);
 | 
						|
	
 | 
						|
	BLI_buildAdjacencyList((BGraph *)rg);
 | 
						|
	
 | 
						|
	RIG_findHead(rg);
 | 
						|
 | 
						|
	BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
 | 
						|
	
 | 
						|
	RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
 | 
						|
	
 | 
						|
	if (BLI_isGraphCyclic((BGraph *)rg)) {
 | 
						|
		printf("armature cyclic\n");
 | 
						|
	}
 | 
						|
	
 | 
						|
	return rg;
 | 
						|
}
 | 
						|
 | 
						|
static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm)
 | 
						|
{
 | 
						|
	Object *obedit = CTX_data_edit_object(C);
 | 
						|
	Scene *scene = CTX_data_scene(C);
 | 
						|
	EditBone *ebone;
 | 
						|
	RigGraph *rg;
 | 
						|
 | 
						|
	rg = newRigGraph();
 | 
						|
	
 | 
						|
	if (obedit == ob) {
 | 
						|
		rg->editbones = arm->edbo;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
 | 
						|
		make_boneList(rg->editbones, &arm->bonebase, NULL, NULL);
 | 
						|
		rg->flag |= RIG_FREE_BONELIST;
 | 
						|
	}
 | 
						|
 | 
						|
	rg->ob = ob;
 | 
						|
 | 
						|
	/* Do the rotations */
 | 
						|
	for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
 | 
						|
		if (ebone->parent == NULL) {
 | 
						|
			RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	BLI_removeDoubleNodes((BGraph *)rg, 0.001);
 | 
						|
	
 | 
						|
	RIG_removeNormalNodes(rg);
 | 
						|
	
 | 
						|
	RIG_removeUneededOffsets(rg);
 | 
						|
	
 | 
						|
	BLI_buildAdjacencyList((BGraph *)rg);
 | 
						|
	
 | 
						|
	RIG_findHead(rg);
 | 
						|
 | 
						|
	BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
 | 
						|
	
 | 
						|
	RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
 | 
						|
	
 | 
						|
	if (BLI_isGraphCyclic((BGraph *)rg)) {
 | 
						|
		printf("armature cyclic\n");
 | 
						|
	}
 | 
						|
	
 | 
						|
	return rg;
 | 
						|
}
 | 
						|
/************************************ GENERATING *****************************************************/
 | 
						|
 | 
						|
#if 0
 | 
						|
static EditBone *add_editbonetolist(char *name, ListBase *list)
 | 
						|
{
 | 
						|
	EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
 | 
						|
	
 | 
						|
	BLI_strncpy(bone->name, name, sizeof(bone->name));
 | 
						|
	unique_editbone_name(list, bone->name, NULL);
 | 
						|
	
 | 
						|
	BLI_addtail(list, bone);
 | 
						|
	
 | 
						|
	bone->flag |= BONE_TIPSEL;
 | 
						|
	bone->weight = 1.0F;
 | 
						|
	bone->dist = 0.25F;
 | 
						|
	bone->xwidth = 0.1;
 | 
						|
	bone->zwidth = 0.1;
 | 
						|
	bone->ease1 = 1.0;
 | 
						|
	bone->ease2 = 1.0;
 | 
						|
	bone->rad_head = 0.10;
 | 
						|
	bone->rad_tail = 0.05;
 | 
						|
	bone->segments = 1;
 | 
						|
	bone->layer =  1; //arm->layer;
 | 
						|
	
 | 
						|
	return bone;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#if 0 /* UNUSED */
 | 
						|
static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit)
 | 
						|
{
 | 
						|
	while (node->multi_level > multi_level_limit && node->link_up)
 | 
						|
	{
 | 
						|
		node = node->link_up;
 | 
						|
	}
 | 
						|
	
 | 
						|
	while (node->multi_level < multi_level_limit && node->link_down)
 | 
						|
	{
 | 
						|
		node = node->link_down;
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (node->multi_level == multi_level_limit)
 | 
						|
	{
 | 
						|
		int i;
 | 
						|
		
 | 
						|
		for (i = 0; i < node->degree; i++)
 | 
						|
		{
 | 
						|
			ReebArc *earc = node->arcs[i];
 | 
						|
			
 | 
						|
			if (earc->flag == ARC_FREE && earc->head == node)
 | 
						|
			{
 | 
						|
				ReebNode *other = BIF_otherNodeFromIndex(earc, node);
 | 
						|
				
 | 
						|
				earc->flag = ARC_USED;
 | 
						|
				
 | 
						|
				//generateBonesForArc(rigg, earc, node, other);
 | 
						|
				generateMissingArcsFromNode(rigg, other, multi_level_limit);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void generateMissingArcs(RigGraph *rigg)
 | 
						|
{
 | 
						|
	ReebGraph *reebg;
 | 
						|
	int multi_level_limit = 5;
 | 
						|
	
 | 
						|
	for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up)
 | 
						|
	{
 | 
						|
		ReebArc *earc;
 | 
						|
		
 | 
						|
		for (earc = reebg->arcs.first; earc; earc = earc->next)
 | 
						|
		{
 | 
						|
			if (earc->flag == ARC_USED)
 | 
						|
			{
 | 
						|
				generateMissingArcsFromNode(rigg, earc->head, multi_level_limit);
 | 
						|
				generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/************************************ RETARGETTING *****************************************************/
 | 
						|
 | 
						|
static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize);
 | 
						|
 | 
						|
static void repositionTailControl(RigGraph *rigg, RigControl *ctrl);
 | 
						|
 | 
						|
static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize)
 | 
						|
{
 | 
						|
	if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) {
 | 
						|
		RigControl *ctrl_child;
 | 
						|
 | 
						|
#if 0		
 | 
						|
		printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name);
 | 
						|
		
 | 
						|
		if (ctrl->link_tail)
 | 
						|
		{
 | 
						|
			printf(" TAIL: %s", ctrl->link_tail->name);
 | 
						|
		}
 | 
						|
		
 | 
						|
		printf("\n");
 | 
						|
#endif
 | 
						|
		
 | 
						|
		/* if there was a tail link: apply link, recalc resize factor and qrot */
 | 
						|
		if (ctrl->tail_mode != TL_NONE) {
 | 
						|
			float *tail_vec = NULL;
 | 
						|
			float v1[3], v2[3], qtail[4];
 | 
						|
			
 | 
						|
			if (ctrl->tail_mode == TL_TAIL) {
 | 
						|
				tail_vec = ctrl->link_tail->tail;
 | 
						|
			}
 | 
						|
			else if (ctrl->tail_mode == TL_HEAD) {
 | 
						|
				tail_vec = ctrl->link_tail->head;
 | 
						|
			}
 | 
						|
			
 | 
						|
			sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head);
 | 
						|
			sub_v3_v3v3(v2, tail_vec, ctrl->bone->head);
 | 
						|
			
 | 
						|
			copy_v3_v3(ctrl->bone->tail, tail_vec);
 | 
						|
			
 | 
						|
			rotation_between_vecs_to_quat(qtail, v1, v2);
 | 
						|
			mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot);
 | 
						|
			
 | 
						|
			resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail);
 | 
						|
		}
 | 
						|
		
 | 
						|
		ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot);
 | 
						|
	
 | 
						|
		/* Cascade to connected control bones */
 | 
						|
		for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
 | 
						|
			if (ctrl_child->link == ctrl->bone) {
 | 
						|
				repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize);
 | 
						|
			}
 | 
						|
			if (ctrl_child->link_tail == ctrl->bone) {
 | 
						|
				repositionTailControl(rigg, ctrl_child);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void repositionTailControl(RigGraph *rigg, RigControl *ctrl)
 | 
						|
{
 | 
						|
	ctrl->flag |= RIG_CTRL_TAIL_DONE;
 | 
						|
 | 
						|
	finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */
 | 
						|
}
 | 
						|
 | 
						|
static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize)
 | 
						|
{
 | 
						|
	float parent_offset[3], tail_offset[3];
 | 
						|
	
 | 
						|
	copy_v3_v3(parent_offset, ctrl->offset);
 | 
						|
	mul_v3_fl(parent_offset, resize);
 | 
						|
	mul_qt_v3(qrot, parent_offset);
 | 
						|
	
 | 
						|
	add_v3_v3v3(ctrl->bone->head, head, parent_offset); 
 | 
						|
 | 
						|
	ctrl->flag |= RIG_CTRL_HEAD_DONE;
 | 
						|
 | 
						|
	copy_qt_qt(ctrl->qrot, qrot);
 | 
						|
 | 
						|
	if (ctrl->tail_mode == TL_NONE) {
 | 
						|
		sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head);
 | 
						|
		mul_v3_fl(tail_offset, resize);
 | 
						|
		mul_qt_v3(qrot, tail_offset);
 | 
						|
 | 
						|
		add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset);
 | 
						|
		
 | 
						|
		ctrl->flag |= RIG_CTRL_TAIL_DONE;
 | 
						|
	}
 | 
						|
 | 
						|
	finalizeControl(rigg, ctrl, resize);
 | 
						|
}
 | 
						|
 | 
						|
static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3])
 | 
						|
{
 | 
						|
	Scene *scene = CTX_data_scene(C);
 | 
						|
	EditBone *bone;
 | 
						|
	RigControl *ctrl;
 | 
						|
	float qrot[4], resize;
 | 
						|
	float v1[3], v2[3];
 | 
						|
	float l1, l2;
 | 
						|
	
 | 
						|
	bone = edge->bone;
 | 
						|
	
 | 
						|
	sub_v3_v3v3(v1, edge->tail, edge->head);
 | 
						|
	sub_v3_v3v3(v2, vec1, vec0);
 | 
						|
	
 | 
						|
	l1 = normalize_v3(v1);
 | 
						|
	l2 = normalize_v3(v2);
 | 
						|
 | 
						|
	resize = l2 / l1;
 | 
						|
	
 | 
						|
	rotation_between_vecs_to_quat(qrot, v1, v2);
 | 
						|
	
 | 
						|
	copy_v3_v3(bone->head, vec0);
 | 
						|
	copy_v3_v3(bone->tail, vec1);
 | 
						|
	
 | 
						|
	if (!is_zero_v3(up_axis)) {
 | 
						|
		float qroll[4];
 | 
						|
 | 
						|
		if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) {
 | 
						|
			bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis);
 | 
						|
		}
 | 
						|
		else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) {
 | 
						|
			bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			unit_qt(qroll);
 | 
						|
		}
 | 
						|
		
 | 
						|
		mul_qt_qtqt(qrot, qroll, qrot);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot);
 | 
						|
	}
 | 
						|
 | 
						|
	for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) {
 | 
						|
		if (ctrl->link == bone) {
 | 
						|
			repositionControl(rigg, ctrl, vec0, vec1, qrot, resize);
 | 
						|
		}
 | 
						|
		if (ctrl->link_tail == bone) {
 | 
						|
			repositionTailControl(rigg, ctrl);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static RetargetMode detectArcRetargetMode(RigArc *arc);
 | 
						|
static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start);
 | 
						|
 | 
						|
 | 
						|
static RetargetMode detectArcRetargetMode(RigArc *iarc)
 | 
						|
{
 | 
						|
	RetargetMode mode = RETARGET_AGGRESSIVE;
 | 
						|
	ReebArc *earc = iarc->link_mesh;
 | 
						|
	RigEdge *edge;
 | 
						|
	int large_angle = 0;
 | 
						|
	float avg_angle = 0;
 | 
						|
	/* float avg_length = 0; */ /* UNUSED */
 | 
						|
	int nb_edges = 0;
 | 
						|
	
 | 
						|
	
 | 
						|
	for (edge = iarc->edges.first; edge; edge = edge->next) {
 | 
						|
		avg_angle += edge->angle;
 | 
						|
		nb_edges++;
 | 
						|
	}
 | 
						|
	
 | 
						|
	avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */
 | 
						|
 | 
						|
	/* avg_length = iarc->length / nb_edges; */  /* UNUSED */
 | 
						|
	
 | 
						|
	
 | 
						|
	if (nb_edges > 2) {
 | 
						|
		for (edge = iarc->edges.first; edge; edge = edge->next) {
 | 
						|
			if (fabsf(edge->angle - avg_angle) > (float)(M_PI / 6)) {
 | 
						|
				large_angle = 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (nb_edges == 2 && avg_angle > 0) {
 | 
						|
		large_angle = 1;
 | 
						|
	}
 | 
						|
		
 | 
						|
	
 | 
						|
	if (large_angle == 0) {
 | 
						|
		mode = RETARGET_LENGTH;
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (earc->bcount <= (iarc->count - 1)) {
 | 
						|
		mode = RETARGET_LENGTH;
 | 
						|
	}
 | 
						|
	
 | 
						|
	return mode;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef USE_THREADS
 | 
						|
static void printMovesNeeded(int *positions, int nb_positions)
 | 
						|
{
 | 
						|
	int moves = 0;
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	for (i = 0; i < nb_positions; i++) {
 | 
						|
		moves += positions[i] - (i + 1);
 | 
						|
	}
 | 
						|
	
 | 
						|
	printf("%i moves needed\n", moves);
 | 
						|
}
 | 
						|
 | 
						|
static void printPositions(int *positions, int nb_positions)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	for (i = 0; i < nb_positions; i++) {
 | 
						|
		printf("%i ", positions[i]);
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#define MAX_COST FLT_MAX /* FIX ME */
 | 
						|
 | 
						|
static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight)
 | 
						|
{
 | 
						|
	EmbedBucket *bucket = NULL;
 | 
						|
	float max_dist = 0;
 | 
						|
	float v1[3], v2[3], c[3];
 | 
						|
	float v1_inpf;
 | 
						|
 | 
						|
	if (distance_weight > 0) {
 | 
						|
		sub_v3_v3v3(v1, vec0, vec1);
 | 
						|
		
 | 
						|
		v1_inpf = dot_v3v3(v1, v1);
 | 
						|
		
 | 
						|
		if (v1_inpf > 0) {
 | 
						|
			int j;
 | 
						|
			for (j = i0 + 1; j < i1 - 1; j++) {
 | 
						|
				float dist;
 | 
						|
				
 | 
						|
				bucket = IT_peek(iter, j);
 | 
						|
	
 | 
						|
				sub_v3_v3v3(v2, bucket->p, vec1);
 | 
						|
		
 | 
						|
				cross_v3_v3v3(c, v1, v2);
 | 
						|
				
 | 
						|
				dist = dot_v3v3(c, c) / v1_inpf;
 | 
						|
				
 | 
						|
				max_dist = dist > max_dist ? dist : max_dist;
 | 
						|
			}
 | 
						|
			
 | 
						|
			return distance_weight * max_dist;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			return MAX_COST;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight)
 | 
						|
{
 | 
						|
	if (angle_weight > 0) {
 | 
						|
		float current_angle;
 | 
						|
		
 | 
						|
		if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) {
 | 
						|
			current_angle = saacos(dot_v3v3(vec_first, vec_second));
 | 
						|
 | 
						|
			return angle_weight * fabsf(current_angle - original_angle);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			return angle_weight * (float)M_PI;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static float costLength(float original_length, float current_length, float length_weight)
 | 
						|
{
 | 
						|
	if (current_length == 0) {
 | 
						|
		return MAX_COST;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		float length_ratio = fabsf((current_length - original_length) / original_length);
 | 
						|
		return length_weight * length_ratio * length_ratio;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#if 0
 | 
						|
static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
 | 
						|
{
 | 
						|
	float vec[3];
 | 
						|
	float length;
 | 
						|
 | 
						|
	sub_v3_v3v3(vec, vec2, vec1);
 | 
						|
	length = normalize_v3(vec);
 | 
						|
 | 
						|
	return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge,
 | 
						|
                                         float *vec0, float *vec1, float *vec2, int i1, int i2,
 | 
						|
                                         float angle_weight, float length_weight, float distance_weight)
 | 
						|
{
 | 
						|
	float vec_second[3], vec_first[3];
 | 
						|
	float length2;
 | 
						|
	float new_cost = 0;
 | 
						|
 | 
						|
	sub_v3_v3v3(vec_second, vec2, vec1);
 | 
						|
	length2 = normalize_v3(vec_second);
 | 
						|
 | 
						|
 | 
						|
	/* Angle cost */
 | 
						|
	if (edge->prev) {
 | 
						|
		sub_v3_v3v3(vec_first, vec1, vec0); 
 | 
						|
		normalize_v3(vec_first);
 | 
						|
		
 | 
						|
		new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Length cost */
 | 
						|
	new_cost += costLength(edge->length, length2, length_weight);
 | 
						|
 | 
						|
	/* Distance cost */
 | 
						|
	new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight);
 | 
						|
 | 
						|
	return new_cost;
 | 
						|
}
 | 
						|
 | 
						|
static int indexMemoNode(int nb_positions, int previous, int current, int joints_left)
 | 
						|
{
 | 
						|
	return joints_left * nb_positions * nb_positions + current * nb_positions + previous;
 | 
						|
}
 | 
						|
 | 
						|
static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left)
 | 
						|
{
 | 
						|
	int previous = 0, current = 0;
 | 
						|
	int i = 0;
 | 
						|
	
 | 
						|
	for (i = 0; joints_left > 0; joints_left--, i++) {
 | 
						|
		MemoNode *node;
 | 
						|
		node = table + indexMemoNode(nb_positions, previous, current, joints_left);
 | 
						|
		
 | 
						|
		positions[i] = node->next;
 | 
						|
		
 | 
						|
		previous = current;
 | 
						|
		current = node->next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache,
 | 
						|
                             int nb_joints, int nb_positions, int previous, int current, RigEdge *edge,
 | 
						|
                             int joints_left, float angle_weight, float length_weight, float distance_weight)
 | 
						|
{
 | 
						|
	MemoNode *node;
 | 
						|
	int index = indexMemoNode(nb_positions, previous, current, joints_left);
 | 
						|
	
 | 
						|
	node = table + index;
 | 
						|
	
 | 
						|
	if (node->weight != 0) {
 | 
						|
		return node;
 | 
						|
	}
 | 
						|
	else if (joints_left == 0) {
 | 
						|
		float *vec0 = vec_cache[previous];
 | 
						|
		float *vec1 = vec_cache[current];
 | 
						|
		float *vec2 = vec_cache[nb_positions + 1];
 | 
						|
 | 
						|
		node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight);
 | 
						|
 | 
						|
		return node;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		MemoNode *min_node = NULL;
 | 
						|
		float *vec0 = vec_cache[previous];
 | 
						|
		float *vec1 = vec_cache[current];
 | 
						|
		float min_weight = 0.0f;
 | 
						|
		int min_next = 0;
 | 
						|
		int next;
 | 
						|
		
 | 
						|
		for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) {
 | 
						|
			MemoNode *next_node;
 | 
						|
			float *vec2 = vec_cache[next];
 | 
						|
			float weight = 0.0f;
 | 
						|
			
 | 
						|
			/* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */
 | 
						|
			weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight);
 | 
						|
			
 | 
						|
			if (weight >= MAX_COST) {
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			
 | 
						|
			/* add node weight */
 | 
						|
			next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight);
 | 
						|
			weight += next_node->weight;
 | 
						|
			
 | 
						|
			if (min_node == NULL || weight < min_weight) {
 | 
						|
				min_weight = weight;
 | 
						|
				min_node = next_node;
 | 
						|
				min_next = next;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (min_node) {
 | 
						|
			node->weight = min_weight;
 | 
						|
			node->next = min_next;
 | 
						|
			return node;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			node->weight = MAX_COST;
 | 
						|
			return node;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
}
 | 
						|
 | 
						|
static int testFlipArc(RigArc *iarc, RigNode *inode_start)
 | 
						|
{
 | 
						|
	ReebArc *earc = iarc->link_mesh;
 | 
						|
	ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh);
 | 
						|
	
 | 
						|
	/* no flip needed if both nodes are the same */
 | 
						|
	if ((enode_start == earc->head && inode_start == iarc->head) ||
 | 
						|
	    (enode_start == earc->tail && inode_start == iarc->tail))
 | 
						|
	{
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
 | 
						|
{
 | 
						|
	ReebArcIterator arc_iter;
 | 
						|
	BArcIterator *iter = (BArcIterator *)&arc_iter;
 | 
						|
	RigEdge *edge;
 | 
						|
	ReebNode *node_start, *node_end;
 | 
						|
	ReebArc *earc = iarc->link_mesh;
 | 
						|
	float angle_weight = 1.0; // GET FROM CONTEXT
 | 
						|
	float length_weight = 1.0;
 | 
						|
	float distance_weight = 1.0;
 | 
						|
#ifndef USE_THREADS
 | 
						|
	float min_cost = FLT_MAX;
 | 
						|
#endif
 | 
						|
	float *vec0, *vec1;
 | 
						|
	int *best_positions;
 | 
						|
	int nb_edges = BLI_listbase_count(&iarc->edges);
 | 
						|
	int nb_joints = nb_edges - 1;
 | 
						|
	RetargetMethod method = METHOD_MEMOIZE;
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	if (nb_joints > earc->bcount) {
 | 
						|
		printf("NOT ENOUGH BUCKETS!\n");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions");
 | 
						|
	
 | 
						|
	if (testFlipArc(iarc, inode_start)) {
 | 
						|
		node_start = earc->tail;
 | 
						|
		node_end = earc->head;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		node_start = earc->head;
 | 
						|
		node_end = earc->tail;
 | 
						|
	}
 | 
						|
 | 
						|
	/* equal number of joints and potential position, just fill them in */
 | 
						|
	if (nb_joints == earc->bcount) {
 | 
						|
		/* init with first values */
 | 
						|
		for (i = 0; i < nb_joints; i++) {
 | 
						|
			best_positions[i] = i + 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (method == METHOD_MEMOIZE) {
 | 
						|
		int nb_positions = earc->bcount;
 | 
						|
		int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1);
 | 
						|
		MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table");
 | 
						|
#ifndef USE_THREADS
 | 
						|
		MemoNode *result;
 | 
						|
#endif
 | 
						|
		float **positions_cache = MEM_callocN(sizeof(float *) * (nb_positions + 2), "positions cache");
 | 
						|
		
 | 
						|
		positions_cache[0] = node_start->p;
 | 
						|
		positions_cache[nb_positions + 1] = node_end->p;
 | 
						|
		
 | 
						|
		initArcIterator(iter, earc, node_start);
 | 
						|
 | 
						|
		for (i = 1; i <= nb_positions; i++) {
 | 
						|
			EmbedBucket *bucket = IT_peek(iter, i);
 | 
						|
			positions_cache[i] = bucket->p;
 | 
						|
		}
 | 
						|
 | 
						|
#ifndef USE_THREADS
 | 
						|
		result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
 | 
						|
		min_cost = result->weight;
 | 
						|
#else
 | 
						|
		solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
 | 
						|
#endif
 | 
						|
 | 
						|
		copyMemoPositions(best_positions, table, earc->bcount, nb_joints);
 | 
						|
 | 
						|
		MEM_freeN(table);
 | 
						|
		MEM_freeN(positions_cache);
 | 
						|
	}
 | 
						|
 | 
						|
	vec0 = node_start->p;
 | 
						|
	initArcIterator(iter, earc, node_start);
 | 
						|
	
 | 
						|
#ifndef USE_THREADS
 | 
						|
	printPositions(best_positions, nb_joints);
 | 
						|
	printMovesNeeded(best_positions, nb_joints);
 | 
						|
	printf("min_cost %f\n", min_cost);
 | 
						|
	printf("buckets: %i\n", earc->bcount);
 | 
						|
#endif
 | 
						|
 | 
						|
	/* set joints to best position */
 | 
						|
	for (edge = iarc->edges.first, i = 0;
 | 
						|
	     edge;
 | 
						|
	     edge = edge->next, i++)
 | 
						|
	{
 | 
						|
		float *no = NULL;
 | 
						|
		if (i < nb_joints) {
 | 
						|
			EmbedBucket *bucket = IT_peek(iter, best_positions[i]);
 | 
						|
			vec1 = bucket->p;
 | 
						|
			no = bucket->no;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			vec1 = node_end->p;
 | 
						|
			no = node_end->no;
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (edge->bone) {
 | 
						|
			repositionBone(C, rigg, edge, vec0, vec1, no);
 | 
						|
		}
 | 
						|
		
 | 
						|
		vec0 = vec1;
 | 
						|
	}
 | 
						|
 | 
						|
	MEM_freeN(best_positions);
 | 
						|
}
 | 
						|
 | 
						|
static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
 | 
						|
{
 | 
						|
	ReebArcIterator arc_iter;
 | 
						|
	BArcIterator *iter = (BArcIterator *)&arc_iter;
 | 
						|
	ReebArc *earc = iarc->link_mesh;
 | 
						|
	ReebNode *node_start, *node_end;
 | 
						|
	RigEdge *edge;
 | 
						|
	EmbedBucket *bucket = NULL;
 | 
						|
	float embedding_length = 0;
 | 
						|
	float *vec0 = NULL;
 | 
						|
	float *vec1 = NULL;
 | 
						|
	float *previous_vec = NULL;
 | 
						|
 | 
						|
	
 | 
						|
	if (testFlipArc(iarc, inode_start)) {
 | 
						|
		node_start = (ReebNode *)earc->tail;
 | 
						|
		node_end = (ReebNode *)earc->head;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		node_start = (ReebNode *)earc->head;
 | 
						|
		node_end = (ReebNode *)earc->tail;
 | 
						|
	}
 | 
						|
	
 | 
						|
	initArcIterator(iter, earc, node_start);
 | 
						|
 | 
						|
	bucket = IT_next(iter);
 | 
						|
	
 | 
						|
	vec0 = node_start->p;
 | 
						|
	
 | 
						|
	while (bucket != NULL) {
 | 
						|
		vec1 = bucket->p;
 | 
						|
		
 | 
						|
		embedding_length += len_v3v3(vec0, vec1);
 | 
						|
		
 | 
						|
		vec0 = vec1;
 | 
						|
		bucket = IT_next(iter);
 | 
						|
	}
 | 
						|
	
 | 
						|
	embedding_length += len_v3v3(node_end->p, vec1);
 | 
						|
	
 | 
						|
	/* fit bones */
 | 
						|
	initArcIterator(iter, earc, node_start);
 | 
						|
 | 
						|
	bucket = IT_next(iter);
 | 
						|
 | 
						|
	vec0 = node_start->p;
 | 
						|
	previous_vec = vec0;
 | 
						|
	vec1 = bucket->p;
 | 
						|
	
 | 
						|
	for (edge = iarc->edges.first; edge; edge = edge->next) {
 | 
						|
		float new_bone_length = edge->length / iarc->length * embedding_length;
 | 
						|
		float *no = NULL;
 | 
						|
		float length = 0;
 | 
						|
 | 
						|
		while (bucket && new_bone_length > length) {
 | 
						|
			length += len_v3v3(previous_vec, vec1);
 | 
						|
			bucket = IT_next(iter);
 | 
						|
			previous_vec = vec1;
 | 
						|
			vec1 = bucket->p;
 | 
						|
			no = bucket->no;
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (bucket == NULL) {
 | 
						|
			vec1 = node_end->p;
 | 
						|
			no = node_end->no;
 | 
						|
		}
 | 
						|
 | 
						|
		/* no need to move virtual edges (space between unconnected bones) */
 | 
						|
		if (edge->bone) {
 | 
						|
			repositionBone(C, rigg, edge, vec0, vec1, no);
 | 
						|
		}
 | 
						|
		
 | 
						|
		vec0 = vec1;
 | 
						|
		previous_vec = vec1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
 | 
						|
{
 | 
						|
	RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam");
 | 
						|
	
 | 
						|
	p->rigg = rigg;
 | 
						|
	p->iarc = iarc;
 | 
						|
	p->inode_start = inode_start;
 | 
						|
	p->context = C;
 | 
						|
	
 | 
						|
	BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH);
 | 
						|
}
 | 
						|
 | 
						|
void exec_retargetArctoArc(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
 | 
						|
{
 | 
						|
	RetargetParam *p = (RetargetParam *)taskdata;
 | 
						|
	RigGraph *rigg = p->rigg;
 | 
						|
	RigArc *iarc = p->iarc;
 | 
						|
	bContext *C = p->context;
 | 
						|
	RigNode *inode_start = p->inode_start;
 | 
						|
	ReebArc *earc = iarc->link_mesh;
 | 
						|
	
 | 
						|
	if (BLI_listbase_is_single(&iarc->edges)) {
 | 
						|
		RigEdge *edge = iarc->edges.first;
 | 
						|
 | 
						|
		if (testFlipArc(iarc, inode_start)) {
 | 
						|
			repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		RetargetMode mode = detectArcRetargetMode(iarc);
 | 
						|
		
 | 
						|
		if (mode == RETARGET_AGGRESSIVE) {
 | 
						|
			retargetArctoArcAggresive(C, rigg, iarc, inode_start);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			retargetArctoArcLength(C, rigg, iarc, inode_start);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node)
 | 
						|
{
 | 
						|
	ReebNode *enode = top_node;
 | 
						|
	ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
 | 
						|
	int ishape, eshape;
 | 
						|
	
 | 
						|
	ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
 | 
						|
	eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
 | 
						|
	
 | 
						|
	inode->link_mesh = enode;
 | 
						|
 | 
						|
	while (ishape == eshape && enode->link_down) {
 | 
						|
		inode->link_mesh = enode;
 | 
						|
 | 
						|
		enode = enode->link_down;
 | 
						|
		reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */
 | 
						|
		eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	for (i = 0; i < enode->degree; i++) {
 | 
						|
		ReebArc *earc = (ReebArc *)enode->arcs[i];
 | 
						|
		
 | 
						|
		if (earc->flag == ARC_FREE) {
 | 
						|
			earc->flag = ARC_TAKEN;
 | 
						|
			
 | 
						|
			if (earc->tail->degree > 1 && earc->tail != end_enode) {
 | 
						|
				markMultiResolutionChildArc(end_enode, earc->tail);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void markMultiResolutionArc(ReebArc *start_earc)
 | 
						|
{
 | 
						|
	if (start_earc->link_up) {
 | 
						|
		ReebArc *earc;
 | 
						|
		for (earc = start_earc->link_up; earc; earc = earc->link_up) {
 | 
						|
			earc->flag = ARC_TAKEN;
 | 
						|
			
 | 
						|
			if (earc->tail->index != start_earc->tail->index) {
 | 
						|
				markMultiResolutionChildArc(earc->tail, earc->tail);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc)
 | 
						|
{
 | 
						|
	ReebNode *enode = next_earc->head;
 | 
						|
	ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
 | 
						|
	int ishape, eshape;
 | 
						|
 | 
						|
	ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)start_node, (BArc *)next_iarc, 1) % SHAPE_LEVELS;
 | 
						|
	eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
 | 
						|
	
 | 
						|
	while (ishape != eshape && next_earc->link_up) {
 | 
						|
		next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels
 | 
						|
		
 | 
						|
		next_earc = next_earc->link_up;
 | 
						|
		reebg = reebg->link_up;
 | 
						|
		enode = next_earc->head;
 | 
						|
		eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
 | 
						|
	}
 | 
						|
 | 
						|
	next_earc->flag = ARC_USED;
 | 
						|
	next_iarc->link_mesh = next_earc;
 | 
						|
	
 | 
						|
	/* mark all higher levels as taken too */
 | 
						|
	markMultiResolutionArc(next_earc);
 | 
						|
//	while (next_earc->link_up)
 | 
						|
//	{
 | 
						|
//		next_earc = next_earc->link_up;
 | 
						|
//		next_earc->flag = ARC_TAKEN;
 | 
						|
//	}
 | 
						|
}
 | 
						|
 | 
						|
static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode)
 | 
						|
{
 | 
						|
	ReebNode *enode;
 | 
						|
	int ishape, eshape;
 | 
						|
	
 | 
						|
	enode = reebg->nodes.first;
 | 
						|
	
 | 
						|
	ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
 | 
						|
	eshape = BLI_subtreeShape((BGraph *)rigg->link_mesh, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
 | 
						|
	
 | 
						|
	while (ishape != eshape && reebg->link_up) {
 | 
						|
		reebg = reebg->link_up;
 | 
						|
		
 | 
						|
		enode = reebg->nodes.first;
 | 
						|
		
 | 
						|
		eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
 | 
						|
	}
 | 
						|
 | 
						|
	inode->link_mesh = enode;
 | 
						|
}
 | 
						|
 | 
						|
static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root)
 | 
						|
{
 | 
						|
	ReebNode *enode = start_node->link_mesh;
 | 
						|
	ReebArc *next_earc;
 | 
						|
	int symmetry_level = next_iarc->symmetry_level;
 | 
						|
	int symmetry_group = next_iarc->symmetry_group;
 | 
						|
	int symmetry_flag = next_iarc->symmetry_flag;
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	next_iarc->link_mesh = NULL;
 | 
						|
		
 | 
						|
//	if (root)
 | 
						|
//	{
 | 
						|
//		printf("-----------------------\n");
 | 
						|
//		printf("MATCHING LIMB\n");
 | 
						|
//		RIG_printArcBones(next_iarc);
 | 
						|
//	}
 | 
						|
	
 | 
						|
	for (i = 0; i < enode->degree; i++) {
 | 
						|
		next_earc = (ReebArc *)enode->arcs[i];
 | 
						|
		
 | 
						|
//		if (next_earc->flag == ARC_FREE)
 | 
						|
//		{
 | 
						|
//			printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n",
 | 
						|
//			symmetry_level, next_earc->symmetry_level,
 | 
						|
//			symmetry_flag, next_earc->symmetry_flag, 
 | 
						|
//			symmetry_group, next_earc->symmetry_flag);
 | 
						|
//		}
 | 
						|
		
 | 
						|
		if (next_earc->flag == ARC_FREE &&
 | 
						|
		    next_earc->symmetry_flag == symmetry_flag &&
 | 
						|
		    next_earc->symmetry_group == symmetry_group &&
 | 
						|
		    next_earc->symmetry_level == symmetry_level)
 | 
						|
		{
 | 
						|
//			printf("CORRESPONDING ARC FOUND\n");
 | 
						|
//			printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
 | 
						|
			
 | 
						|
			matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	/* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */
 | 
						|
	if (next_iarc->link_mesh == NULL) {
 | 
						|
//		printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n");
 | 
						|
		
 | 
						|
		if (enode->link_up) {
 | 
						|
			start_node->link_mesh = enode->link_up;
 | 
						|
			findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* still not found, print debug info */
 | 
						|
	if (root && next_iarc->link_mesh == NULL) {
 | 
						|
		start_node->link_mesh = enode; /* linking back with root node */
 | 
						|
		
 | 
						|
//		printf("NO CORRESPONDING ARC FOUND\n");
 | 
						|
//		RIG_printArcBones(next_iarc);
 | 
						|
//		
 | 
						|
//		printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level);
 | 
						|
//		
 | 
						|
//		printf("LOOKING FOR\n");
 | 
						|
//		printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group);
 | 
						|
//		
 | 
						|
//		printf("CANDIDATES\n");
 | 
						|
//		for (i = 0; i < enode->degree; i++)
 | 
						|
//		{
 | 
						|
//			next_earc = (ReebArc *)enode->arcs[i];
 | 
						|
//			printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
 | 
						|
//		}
 | 
						|
		
 | 
						|
		/* Emergency matching */
 | 
						|
		for (i = 0; i < enode->degree; i++) {
 | 
						|
			next_earc = (ReebArc *)enode->arcs[i];
 | 
						|
			
 | 
						|
			if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) {
 | 
						|
//				printf("USING:\n");
 | 
						|
//				printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
 | 
						|
				matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node)
 | 
						|
{
 | 
						|
	RigNode *inode = start_node;
 | 
						|
	int i;
 | 
						|
 | 
						|
	/* no start arc on first node */
 | 
						|
	if (start_arc) {
 | 
						|
		ReebNode *enode = start_node->link_mesh;
 | 
						|
		ReebArc *earc = start_arc->link_mesh;
 | 
						|
		
 | 
						|
		retargetArctoArc(C, rigg, start_arc, start_node);
 | 
						|
		
 | 
						|
		enode = BIF_otherNodeFromIndex(earc, enode);
 | 
						|
		inode = (RigNode *)BLI_otherNode((BArc *)start_arc, (BNode *)inode);
 | 
						|
	
 | 
						|
		/* match with lowest node with correct shape */
 | 
						|
		matchMultiResolutionNode(rigg, inode, enode);
 | 
						|
	}
 | 
						|
	
 | 
						|
	for (i = 0; i < inode->degree; i++) {
 | 
						|
		RigArc *next_iarc = (RigArc *)inode->arcs[i];
 | 
						|
		
 | 
						|
		/* no back tracking */
 | 
						|
		if (next_iarc != start_arc) {
 | 
						|
			findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1);
 | 
						|
			if (next_iarc->link_mesh) {
 | 
						|
				retargetSubgraph(C, rigg, next_iarc, inode);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void finishRetarget(RigGraph *rigg)
 | 
						|
{
 | 
						|
	BLI_task_pool_work_and_wait(rigg->task_pool);
 | 
						|
}
 | 
						|
 | 
						|
static void adjustGraphs(bContext *C, RigGraph *rigg)
 | 
						|
{
 | 
						|
	bArmature *arm = rigg->ob->data;
 | 
						|
	RigArc *arc;
 | 
						|
	
 | 
						|
	for (arc = rigg->arcs.first; arc; arc = arc->next) {
 | 
						|
		if (arc->link_mesh) {
 | 
						|
			retargetArctoArc(C, rigg, arc, arc->head);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	finishRetarget(rigg);
 | 
						|
 | 
						|
	/* Turn the list into an armature */
 | 
						|
	arm->edbo = rigg->editbones;
 | 
						|
	ED_armature_from_edit(arm);
 | 
						|
	
 | 
						|
	ED_undo_push(C, "Retarget Skeleton");
 | 
						|
}
 | 
						|
 | 
						|
static void retargetGraphs(bContext *C, RigGraph *rigg)
 | 
						|
{
 | 
						|
	bArmature *arm = rigg->ob->data;
 | 
						|
	ReebGraph *reebg = rigg->link_mesh;
 | 
						|
	RigNode *inode;
 | 
						|
	
 | 
						|
	/* flag all ReebArcs as free */
 | 
						|
	BIF_flagMultiArcs(reebg, ARC_FREE);
 | 
						|
	
 | 
						|
	/* return to first level */
 | 
						|
	inode = rigg->head;
 | 
						|
	
 | 
						|
	matchMultiResolutionStartingNode(rigg, reebg, inode);
 | 
						|
 | 
						|
	retargetSubgraph(C, rigg, NULL, inode);
 | 
						|
	
 | 
						|
	//generateMissingArcs(rigg);
 | 
						|
	
 | 
						|
	finishRetarget(rigg);
 | 
						|
 | 
						|
	/* Turn the list into an armature */
 | 
						|
	arm->edbo = rigg->editbones;
 | 
						|
	ED_armature_from_edit(arm);
 | 
						|
}
 | 
						|
 | 
						|
const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index)
 | 
						|
{
 | 
						|
	RigArc *arc = BLI_findlink(&rg->arcs, arc_index);
 | 
						|
	RigEdge *iedge;
 | 
						|
 | 
						|
	if (arc == NULL) {
 | 
						|
		return "None";
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (bone_index == BLI_listbase_count(&arc->edges)) {
 | 
						|
		return "Last joint";
 | 
						|
	}
 | 
						|
 | 
						|
	iedge = BLI_findlink(&arc->edges, bone_index);
 | 
						|
	
 | 
						|
	if (iedge == NULL) {
 | 
						|
		return "Done";
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (iedge->bone == NULL) {
 | 
						|
		return "Bone offset";
 | 
						|
	}
 | 
						|
	
 | 
						|
	return iedge->bone->name;
 | 
						|
}
 | 
						|
 | 
						|
int RIG_nbJoints(RigGraph *rg)
 | 
						|
{
 | 
						|
	RigArc *arc;
 | 
						|
	int total = 0;
 | 
						|
	
 | 
						|
	total += BLI_listbase_count(&rg->nodes);
 | 
						|
	
 | 
						|
	for (arc = rg->arcs.first; arc; arc = arc->next) {
 | 
						|
		total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */
 | 
						|
	}
 | 
						|
	
 | 
						|
	return total;
 | 
						|
}
 | 
						|
 | 
						|
static void BIF_freeRetarget(void)
 | 
						|
{
 | 
						|
	if (GLOBAL_RIGG) {
 | 
						|
		RIG_freeRigGraph((BGraph *)GLOBAL_RIGG);
 | 
						|
		GLOBAL_RIGG = NULL;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void BIF_retargetArmature(bContext *C)
 | 
						|
{
 | 
						|
	ReebGraph *reebg;
 | 
						|
	double start_time, end_time;
 | 
						|
	double gstart_time, gend_time;
 | 
						|
	double reeb_time, rig_time = 0.0, retarget_time = 0.0, total_time;
 | 
						|
	
 | 
						|
	gstart_time = start_time = PIL_check_seconds_timer();
 | 
						|
	
 | 
						|
	reebg = BIF_ReebGraphMultiFromEditMesh(C);
 | 
						|
	
 | 
						|
	end_time = PIL_check_seconds_timer();
 | 
						|
	reeb_time = end_time - start_time;
 | 
						|
	
 | 
						|
	printf("Reeb Graph created\n");
 | 
						|
 | 
						|
	CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
 | 
						|
	{
 | 
						|
		Object *ob = base->object;
 | 
						|
 | 
						|
		if (ob->type == OB_ARMATURE) {
 | 
						|
			RigGraph *rigg;
 | 
						|
			bArmature *arm;
 | 
						|
 | 
						|
			arm = ob->data;
 | 
						|
		
 | 
						|
			/* Put the armature into editmode */
 | 
						|
			
 | 
						|
		
 | 
						|
			start_time = PIL_check_seconds_timer();
 | 
						|
 | 
						|
			rigg = RIG_graphFromArmature(C, ob, arm);
 | 
						|
			
 | 
						|
			end_time = PIL_check_seconds_timer();
 | 
						|
			rig_time = end_time - start_time;
 | 
						|
 | 
						|
			printf("Armature graph created\n");
 | 
						|
	
 | 
						|
			//RIG_printGraph(rigg);
 | 
						|
			
 | 
						|
			rigg->link_mesh = reebg;
 | 
						|
			
 | 
						|
			printf("retargetting %s\n", ob->id.name);
 | 
						|
			
 | 
						|
			start_time = PIL_check_seconds_timer();
 | 
						|
 | 
						|
			retargetGraphs(C, rigg);
 | 
						|
			
 | 
						|
			end_time = PIL_check_seconds_timer();
 | 
						|
			retarget_time = end_time - start_time;
 | 
						|
 | 
						|
			BIF_freeRetarget();
 | 
						|
			
 | 
						|
			GLOBAL_RIGG = rigg;
 | 
						|
			
 | 
						|
			break; /* only one armature at a time */
 | 
						|
		}
 | 
						|
	}
 | 
						|
	CTX_DATA_END;
 | 
						|
 | 
						|
	
 | 
						|
	gend_time = PIL_check_seconds_timer();
 | 
						|
 | 
						|
	total_time = gend_time - gstart_time;
 | 
						|
 | 
						|
	printf("-----------\n");
 | 
						|
	printf("runtime: \t%.3f\n", total_time);
 | 
						|
	printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100);
 | 
						|
	printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100);
 | 
						|
	printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100);
 | 
						|
	printf("-----------\n");
 | 
						|
	
 | 
						|
	ED_undo_push(C, "Retarget Skeleton");
 | 
						|
 | 
						|
	// XXX
 | 
						|
//	allqueue(REDRAWVIEW3D, 0);
 | 
						|
}
 | 
						|
 | 
						|
void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg)
 | 
						|
{
 | 
						|
	Object *obedit = CTX_data_edit_object(C);
 | 
						|
	Scene *scene = CTX_data_scene(C);
 | 
						|
	bArmature *armedit = obedit->data;
 | 
						|
	Object *ob;
 | 
						|
	RigGraph *rigg;
 | 
						|
	RigArc *iarc;
 | 
						|
	char *side_string = scene->toolsettings->skgen_side_string;
 | 
						|
	char *num_string = scene->toolsettings->skgen_num_string;
 | 
						|
	int free_template = 0;
 | 
						|
	
 | 
						|
	if (template_rigg) {
 | 
						|
		ob = template_rigg->ob;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		free_template = 1;
 | 
						|
		ob = obedit;
 | 
						|
		template_rigg = armatureSelectedToGraph(C, ob, ob->data);
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (BLI_listbase_is_empty(&template_rigg->arcs)) {
 | 
						|
//		XXX
 | 
						|
//		error("No Template and no deforming bones selected");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	
 | 
						|
	rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string);
 | 
						|
	
 | 
						|
	iarc = rigg->arcs.first;
 | 
						|
	
 | 
						|
	iarc->link_mesh = earc;
 | 
						|
	iarc->head->link_mesh = earc->head;
 | 
						|
	iarc->tail->link_mesh = earc->tail;
 | 
						|
	
 | 
						|
	retargetArctoArc(C, rigg, iarc, iarc->head);
 | 
						|
	
 | 
						|
	finishRetarget(rigg);
 | 
						|
	
 | 
						|
	/* free template if it comes from the edit armature */
 | 
						|
	if (free_template) {
 | 
						|
		RIG_freeRigGraph((BGraph *)template_rigg);
 | 
						|
	}
 | 
						|
	RIG_freeRigGraph((BGraph *)rigg);
 | 
						|
	
 | 
						|
	ED_armature_validate_active(armedit);
 | 
						|
 | 
						|
//	XXX
 | 
						|
//	allqueue(REDRAWVIEW3D, 0);
 | 
						|
}
 | 
						|
 | 
						|
void BIF_adjustRetarget(bContext *C)
 | 
						|
{
 | 
						|
	if (GLOBAL_RIGG) {
 | 
						|
		adjustGraphs(C, GLOBAL_RIGG);
 | 
						|
	}
 | 
						|
}
 |