Blob Blame Raw
/* === S Y N F I G ========================================================= */
/*!	\file bone.h
**	\brief Bone Header
**
**	$Id$
**
**	\legal
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**	Copyright (c) 2008 Carlos López & Chirs Moore
**
**	This package 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 package 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.
**	\endlegal
*/
/* ========================================================================= */

/* === S T A R T =========================================================== */

#ifndef __SYNFIG_BONE_H
#define __SYNFIG_BONE_H

/* === H E A D E R S ======================================================= */
#include <iostream>
#include "matrix.h"
#include "uniqueid.h"
#include "string.h"
#include "guid.h"
#include <vector>
#include <ETL/handle>

/* === M A C R O S ========================================================= */

// how many hex digits of the guid string to show in debug messages
#define GUID_PREFIX_LEN 6

#define COUT_BONE(bone)													  \
	cout<<"[name]="<<bone.name_<<endl;									  \
	cout<<"[origin]="<<bone.origin_<<endl;	                              \
	cout<<"[angle]="<<bone.angle_<<endl;		                          \
	cout<<"[scalelx]="<<bone.scalelx_<<endl; \
	cout<<"[scalex]="<<bone.scalex_<<endl;	  \
	cout<<"[length]="<<bone.length_<<endl;         \
	cout<<"[width]="<<bone.width_<<endl; \
	cout<<"[tipwidth]="<<bone.tipwidth_<<endl; \
	cout<<"[depth]="<<bone.depth_<<endl; \
	cout<<"[parent]="<<bone.parent_<<endl

/* === T Y P E D E F S ===================================================== */

/* === C L A S S E S & S T R U C T S ======================================= */
namespace synfig {

class ValueNode_Bone;

class Bone: public UniqueID
{
	/*
 --	** -- T Y P E S -----------------------------------------------------------
	*/

public:
	typedef etl::handle<Bone> Handle;

	struct Shape {
		Vector p0;
		Real r0;
		Vector p1;
		Real r1;
		inline Shape():
			r0(0.0), r1(0.0) { }
		inline Shape(const Vector &p0, Real r0, const Vector &p1, Real r1):
			p0(p0), r0(r0), p1(p1), r1(r1) { }
	};

	// typedef etl::loose_handle<Bone> LooseHandle;

	/*
 --	** -- D A T A -------------------------------------------------------------
	*/

private:
	//!This is the name of the bone
	String name_;
	//!This is the current origin of the bone relative to parent
	Point origin_;
	//!This is the current angle if the bone relative to parent.
	Angle angle_;
	//!This is the current local x scale of the bone.
	Real scalelx_;
	//!This is the current recursive x scale of the bone.
	Real scalex_;
	//!This is the current recursive y scale of the bone.
	Real length_;
	//!This is the width of bone at its origin
	Real width_;
	//!This is the width of bone at its tip
	Real tipwidth_;
	//!This is the z-depth of bone
	Real depth_;
	//!The parent bone.
	const ValueNode_Bone* parent_;

	Matrix animated_matrix_;

public:
	//!Default constructor
	Bone();
	//!Constructor by origin and tip
	Bone(const Point &origin, const Point &tip);
	//!Constructor by origin, length and parent (default no parent)
	Bone(const String &name, const Point &origin, const Angle &angle, const Real &length, ValueNode_Bone* p=0);
	//!Wrappers for name_
	const String& get_name()const {return name_;}
	void set_name(const String &x) {name_=x;}

	//!Wrappers for origin_
	const Point& get_origin()const {return origin_;}
	void set_origin(const Point &x) {origin_=x;}

	//!Wrappers for angle_
	const Angle& get_angle()const {return angle_;}
	void set_angle(const Angle &x) {angle_=x;}

	//!Wrapper for scalelx
	const Real& get_scalelx()const {return scalelx_;}
	void set_scalelx(const Real &x) {scalelx_=x;}

	//!Wrapper for scalex
	const Real& get_scalex()const {return scalex_;}
	void set_scalex(const Real &x) {scalex_=x;}

	//!Wrapper for length. Notice that a length of 0 is not allowed.
	const Real& get_length()const {return length_;}
	void set_length(const Real &x) {length_=x<0.00001?0.00001:x;}

	//!Wrapper for width
	const Real& get_width()const {return width_;}
	void set_width(const Real &x) {width_=x;}
	
	//!Wrapper for tipwidth
	const Real& get_tipwidth()const {return tipwidth_;}
	void set_tipwidth(const Real &x) {tipwidth_=x;}

	//!Wrapper for depth
	const Real& get_depth()const {return depth_;}
	void set_depth(const Real &x) {depth_=x;}

	//!This gets the calculated tip of the bone based on
	//!tip=origin+[length,0]*Rotate(alpha)*Scalex(scalex*scalelx)
	Point get_tip();

	//!Wrapper for parent bone
	// const Bone &get_parent() {return *parent_;}
	const ValueNode_Bone* get_parent()const;
	void set_parent(const ValueNode_Bone* parent);

	void add_bone_to_map();
	Bone* find_bone_in_map(int uid);

	//!Animated Transformation matrix.
	//!This matrix applied to a setup point in local
	//!coordinates (the one obtained form the Setup
	//!Transformation matrix) would obtain the
	//!animated position of the point due the current
	//!bone influence
	Matrix get_animated_matrix() const { return animated_matrix_; }
	void set_animated_matrix(Matrix x) { animated_matrix_ = x; }

	Vector get_local_scale() const { return Vector(scalelx_, 1.0); }

	//!Get the string of the Bone
	//!@return String type. A string representation of the bone
	//!components.
	synfig::String get_string()const;

	bool is_root()const;

	Shape get_shape() const;

	static Real distance_to_shape_center_percent(const Shape &shape, const Vector &x);
	static Real influence_function(Real distance_percent);

	static Real influence_percent(const Shape &shape, const Vector &x)
		{ return influence_function(distance_to_shape_center_percent(shape, x)); }

	Real distance_to_shape_center_percent(const Vector &x)const
		{ return distance_to_shape_center_percent(get_shape(), x); }

	Real influence_percent(const Vector &x)const
		{ return influence_percent(get_shape(), x); }

	// checks if point belongs to the range of influence of current bone
	bool have_influence_on(const Vector &x)const
		{ return distance_to_shape_center_percent(x) > 0.0; }
}; // END of class Bone

}; // END of namespace synfig
/* === E N D =============================================================== */

#endif
/*
 * Alternative to Bone *parent_
 * ======================================================================
 * I think that we can leave the bone as a simple information holder
 * and only give it the responsibility of:
 * Set and get:
 * 		-origin,
 * 		-angle,
 * 		-scalelx,
 * 		-scalely,
 * 		-scalex,
 * 		-scaley,
 * 		-length
 * 		-strength,
 * 		-ParentID: this is new: This is the UniqueID value of the parent bone.
 * 		Initially it is set to a non valid number (I think that -1 is fine)
 * 		so it means that it is a root bone. Later an external object can set it
 * 		to a valid UniqueID to mean that that's the parent ID.
 * 		parent_tree is not needed.
 * 		-Skeletons Pointer (see below)
 * Also the bone should:
 * 		-get_animated_matrix
 * 		-get_tip
 *
 * Then it comes the concept of ValueNode_Skeletons. The Skeletons (notice that
 * it is plural because there can be more than one root bone) is like the ValueNode_Bline,
 * a linkable value.
 * It is like a normal list of bones (like bline is a normal list of blinepoints).
 * This list of bones has just that, bones. So the skeleton is not an expandable tree with
 * a potential loop problem; it is just a list of objects.
 *
 * The ValueNode_Skeletons is responsible for:
 * 1) Calculate the complete setup matrix of a bone based on the hierarchy
 * 2) Calculate the complete animated matrix of a bone based on the hierarchy
 * 3) (Re)Parent a bone. Or (Un)Parent it
 * 4) Remove the bone from the list. It would set the parent UniqueID=-1 and the Skeletons
 *    pointer to be 0.
 * 5) Add a new bone to the list. The bone constructor would receive a Skeleton pointer and
 *    eventually a parent UniqueID besides the rest of information to fill the date (origin, etc.).
 *
 * It would look like that:
 *
 *   ValueNode_Skeletons
 *       ValueNode_Bone Bone1
 *       ValueNode_Bone Bone2
 *       ...
 *       ValueNode_Bone BoneN
 *
 * To perform the tasks 1), 2), 3) or 4) the ValueNode_Skeletons should perform a seek into the
 * list of bones by its UniqueID value. For example to calculate the setup matrix it should
 * reconstruct the bone hierarchy from the current bone to the root parent. Due to that now,
 * it is only stored the UniqueID of the parent (and not a pointer), it is the skeletons veluenode
 * who have to perform all the job: find all the parents and multiply in the correct order (depth) its
 * matrixes. The same happen for the animated matrix.
 * For reparent it is the same. It is just a modification of the parent UniqueID.
 * Remove a bone from the list would imply remove all its children from the list. A warning should be triggered.
 * A bone that has a null pointer to Skeletons means that it is orphaned completely. Its parent UniqueID
 * must be -1 in that case. Anyway the bone like that can be used again in other skeleton. Just need to
 * insert it in the Skeletons list by modifying the Skeletons pointer and filling the proper parent UniqueID.
 * The Skeletons pointer is not an animatable ValueNode. It can be a Handle if you like. The parent
 * UniqueID can be animatable.
 * In this way every computation is slower but would be easier to define, visible to the user
 * and more consistent with the ValueNode concept.
 *
 * This variation of concept doesn't imply anything new in the ValueNode_VertexBone.
 * So the ValueNode_VertexBone should look like:
 *
 *   ValueNode_VertexBone
 *       Vertex Free
 *       Vertex Setup
 *       ValueNode_DynamicList Bone_weight_pairs
 *           BoneWeightPair
 *               ValueNode_Bone Bone
 *               Real Weight
 *
 * As well as the Bone having a pointer to the Skeletons it is possible for the VertexBone_ValueNode
 * to calculate the weighted matrixes as stated in the wiki. It just has to retrieve the
 * ValueNode_Skeleton and ask it to perform the known tasks. Later the ValueNode_VertexBone
 * would do the weight calculation.
 *
 * How does it look?
 */