diff options
author | Nathan Letwory <nathan@letworyinteractive.com> | 2010-10-05 04:05:14 +0400 |
---|---|---|
committer | Nathan Letwory <nathan@letworyinteractive.com> | 2010-10-05 04:05:14 +0400 |
commit | 82209cdc86f5f248102df89b3dfeca86149768f7 (patch) | |
tree | 21ce50ed95bc62544d76754c9512ac791e52ca44 /source/blender/collada/SkinInfo.cpp | |
parent | 63b4c93e449902da3bb9a17d4f8b9f8ef7d00ae5 (diff) |
Reorganisation of COLLADA import code. Classes have been split into their own files.
No functional changes.
Where necessary extern "C" {} blocks have been added.
Diffstat (limited to 'source/blender/collada/SkinInfo.cpp')
-rw-r--r-- | source/blender/collada/SkinInfo.cpp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp new file mode 100644 index 00000000000..db6a7a62b54 --- /dev/null +++ b/source/blender/collada/SkinInfo.cpp @@ -0,0 +1,320 @@ +/** + * $Id: DocumentImporter.cpp 32235 2010-10-01 19:46:42Z jesterking $ + * + * ***** 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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <algorithm> + +#include "BKE_object.h" +#include "DNA_armature_types.h" +#include "DNA_modifier_types.h" +#include "ED_mesh.h" +#include "ED_object.h" +#include "BKE_action.h" +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "SkinInfo.h" +#include "collada_utils.h" + +// use this for retrieving bone names, since these must be unique +template<class T> +static const char *bc_get_joint_name(T *node) +{ + const std::string& id = node->getOriginalId(); + return id.size() ? id.c_str() : node->getName().c_str(); +} + +// This is used to store data passed in write_controller_data. +// Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members +// so that arrays don't get freed until we free them explicitly. +SkinInfo::SkinInfo() {} + +SkinInfo::SkinInfo(const SkinInfo& skin) : weights(skin.weights), + joint_data(skin.joint_data), + unit_converter(skin.unit_converter), + ob_arm(skin.ob_arm), + controller_uid(skin.controller_uid), + parent(skin.parent) +{ + copy_m4_m4(bind_shape_matrix, (float (*)[4])skin.bind_shape_matrix); + + transfer_uint_array_data_const(skin.joints_per_vertex, joints_per_vertex); + transfer_uint_array_data_const(skin.weight_indices, weight_indices); + transfer_int_array_data_const(skin.joint_indices, joint_indices); +} + +SkinInfo::SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(NULL), parent(NULL) {} + +// nobody owns the data after this, so it should be freed manually with releaseMemory +template <class T> +void SkinInfo::transfer_array_data(T& src, T& dest) +{ + dest.setData(src.getData(), src.getCount()); + src.yieldOwnerShip(); + dest.yieldOwnerShip(); +} + +// when src is const we cannot src.yieldOwnerShip, this is used by copy constructor +void SkinInfo::transfer_int_array_data_const(const COLLADAFW::IntValuesArray& src, COLLADAFW::IntValuesArray& dest) +{ + dest.setData((int*)src.getData(), src.getCount()); + dest.yieldOwnerShip(); +} + +void SkinInfo::transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest) +{ + dest.setData((unsigned int*)src.getData(), src.getCount()); + dest.yieldOwnerShip(); +} + +void SkinInfo::borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin) +{ + transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointsPerVertex(), joints_per_vertex); + transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getWeightIndices(), weight_indices); + transfer_array_data((COLLADAFW::IntValuesArray&)skin->getJointIndices(), joint_indices); + // transfer_array_data(skin->getWeights(), weights); + + // cannot transfer data for FloatOrDoubleArray, copy values manually + const COLLADAFW::FloatOrDoubleArray& weight = skin->getWeights(); + for (unsigned int i = 0; i < weight.getValuesCount(); i++) + weights.push_back(bc_get_float_value(weight, i)); + + unit_converter->dae_matrix_to_mat4_(bind_shape_matrix, skin->getBindShapeMatrix()); +} + +void SkinInfo::free() +{ + joints_per_vertex.releaseMemory(); + weight_indices.releaseMemory(); + joint_indices.releaseMemory(); + // weights.releaseMemory(); +} + +// using inverse bind matrices to construct armature +// it is safe to invert them to get the original matrices +// because if they are inverse matrices, they can be inverted +void SkinInfo::add_joint(const COLLADABU::Math::Matrix4& matrix) +{ + JointData jd; + unit_converter->dae_matrix_to_mat4_(jd.inv_bind_mat, matrix); + joint_data.push_back(jd); +} + +void SkinInfo::set_controller(const COLLADAFW::SkinController* co) +{ + controller_uid = co->getUniqueId(); + + // fill in joint UIDs + const COLLADAFW::UniqueIdArray& joint_uids = co->getJoints(); + for (unsigned int i = 0; i < joint_uids.getCount(); i++) { + joint_data[i].joint_uid = joint_uids[i]; + + // // store armature pointer + // JointData& jd = joint_index_to_joint_info_map[i]; + // jd.ob_arm = ob_arm; + + // now we'll be able to get inv bind matrix from joint id + // joint_id_to_joint_index_map[joint_ids[i]] = i; + } +} + +// called from write_controller +Object *SkinInfo::create_armature(Scene *scene) +{ + ob_arm = add_object(scene, OB_ARMATURE); + return ob_arm; +} + +Object* SkinInfo::set_armature(Object *ob_arm) +{ + if (this->ob_arm) + return this->ob_arm; + + this->ob_arm = ob_arm; + return ob_arm; +} + +bool SkinInfo::get_joint_inv_bind_matrix(float inv_bind_mat[][4], COLLADAFW::Node *node) +{ + const COLLADAFW::UniqueId& uid = node->getUniqueId(); + std::vector<JointData>::iterator it; + for (it = joint_data.begin(); it != joint_data.end(); it++) { + if ((*it).joint_uid == uid) { + copy_m4_m4(inv_bind_mat, (*it).inv_bind_mat); + return true; + } + } + + return false; +} + +Object *SkinInfo::get_armature() +{ + return ob_arm; +} + +const COLLADAFW::UniqueId& SkinInfo::get_controller_uid() +{ + return controller_uid; +} + +// check if this skin controller references a joint or any descendant of it +// +// some nodes may not be referenced by SkinController, +// in this case to determine if the node belongs to this armature, +// we need to search down the tree +bool SkinInfo::uses_joint_or_descendant(COLLADAFW::Node *node) +{ + const COLLADAFW::UniqueId& uid = node->getUniqueId(); + std::vector<JointData>::iterator it; + for (it = joint_data.begin(); it != joint_data.end(); it++) { + if ((*it).joint_uid == uid) + return true; + } + + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (unsigned int i = 0; i < children.getCount(); i++) { + if (uses_joint_or_descendant(children[i])) + return true; + } + + return false; +} + +void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, + TransformReader *tm) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature); + ((ArmatureModifierData *)md)->object = ob_arm; + + copy_m4_m4(ob->obmat, bind_shape_matrix); + object_apply_mat4(ob, ob->obmat); +#if 1 + bc_set_parent(ob, ob_arm, C); +#else + Object workob; + ob->parent = ob_arm; + ob->partype = PAROBJECT; + + what_does_parent(scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + + ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; + + DAG_scene_sort(bmain, scene); + DAG_ids_flush_update(bmain, 0); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); +#endif + + ((bArmature*)ob_arm->data)->deformflag = ARM_DEF_VGROUP; + + // create all vertex groups + std::vector<JointData>::iterator it; + int joint_index; + for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) { + const char *name = "Group"; + + // name group by joint node name + if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) { + name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]); + } + + ED_vgroup_add_name(ob, (char*)name); + } + + // <vcount> - number of joints per vertex - joints_per_vertex + // <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices + // ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender? + + // for each vertex in weight indices + // for each bone index in vertex + // add vertex to group at group index + // treat group index -1 specially + + // get def group by index with BLI_findlink + + for (unsigned int vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) { + + unsigned int limit = weight + joints_per_vertex[vertex]; + for ( ; weight < limit; weight++) { + int joint = joint_indices[weight], joint_weight = weight_indices[weight]; + + // -1 means "weight towards the bind shape", we just don't assign it to any group + if (joint != -1) { + bDeformGroup *def = (bDeformGroup*)BLI_findlink(&ob->defbase, joint); + + ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE); + } + } + } +} + +bPoseChannel *SkinInfo::get_pose_channel_from_node(COLLADAFW::Node *node) +{ + return get_pose_channel(ob_arm->pose, bc_get_joint_name(node)); +} + +void SkinInfo::set_parent(Object *_parent) +{ + parent = _parent; +} + +Object* SkinInfo::get_parent() +{ + return parent; +} + +void SkinInfo::find_root_joints(const std::vector<COLLADAFW::Node*> &root_joints, + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, + std::vector<COLLADAFW::Node*>& result) +{ + std::vector<COLLADAFW::Node*>::const_iterator it; + for (it = root_joints.begin(); it != root_joints.end(); it++) { + COLLADAFW::Node *root = *it; + std::vector<JointData>::iterator ji; + for (ji = joint_data.begin(); ji != joint_data.end(); ji++) { + COLLADAFW::Node *joint = joint_by_uid[(*ji).joint_uid]; + if (find_node_in_tree(joint, root)) { + if (std::find(result.begin(), result.end(), root) == result.end()) + result.push_back(root); + } + } + } +} + +bool SkinInfo::find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root) +{ + if (node == tree_root) + return true; + + COLLADAFW::NodePointerArray& children = tree_root->getChildNodes(); + for (unsigned int i = 0; i < children.getCount(); i++) { + if (find_node_in_tree(node, children[i])) + return true; + } + + return false; +}
\ No newline at end of file |