Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorNathan Letwory <nathan@letworyinteractive.com>2010-10-05 04:05:14 +0400
committerNathan Letwory <nathan@letworyinteractive.com>2010-10-05 04:05:14 +0400
commit82209cdc86f5f248102df89b3dfeca86149768f7 (patch)
tree21ce50ed95bc62544d76754c9512ac791e52ca44 /source
parent63b4c93e449902da3bb9a17d4f8b9f8ef7d00ae5 (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')
-rw-r--r--source/blender/blenkernel/BKE_context.h6
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h8
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h8
-rw-r--r--source/blender/blenkernel/BKE_library.h8
-rw-r--r--source/blender/blenkernel/BKE_main.h8
-rw-r--r--source/blender/blenkernel/BKE_scene.h8
-rw-r--r--source/blender/blenkernel/BKE_texture.h8
-rw-r--r--source/blender/collada/AnimationImporter.cpp1149
-rw-r--r--source/blender/collada/AnimationImporter.h132
-rw-r--r--source/blender/collada/ArmatureImporter.cpp585
-rw-r--r--source/blender/collada/ArmatureImporter.h160
-rw-r--r--source/blender/collada/DocumentExporter.cpp30
-rw-r--r--source/blender/collada/DocumentExporter.h6
-rw-r--r--source/blender/collada/DocumentImporter.cpp3181
-rw-r--r--source/blender/collada/DocumentImporter.h5
-rw-r--r--source/blender/collada/MeshImporter.cpp907
-rw-r--r--source/blender/collada/MeshImporter.h150
-rw-r--r--source/blender/collada/SkinInfo.cpp320
-rw-r--r--source/blender/collada/SkinInfo.h133
-rw-r--r--source/blender/collada/TransformReader.cpp125
-rw-r--r--source/blender/collada/TransformReader.h70
-rw-r--r--source/blender/collada/collada.cpp6
-rw-r--r--source/blender/collada/collada_internal.h11
-rw-r--r--source/blender/collada/collada_utils.cpp106
-rw-r--r--source/blender/collada/collada_utils.h50
-rw-r--r--source/blender/editors/include/ED_armature.h8
-rw-r--r--source/blender/editors/include/ED_keyframing.h8
-rw-r--r--source/blender/editors/include/ED_mesh.h8
-rw-r--r--source/blender/editors/include/ED_object.h8
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_texture_types.h8
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h8
-rw-r--r--source/blender/makesrna/intern/rna_screen.c4
-rw-r--r--source/blender/windowmanager/WM_api.h8
-rw-r--r--source/blender/windowmanager/WM_types.h8
35 files changed, 4058 insertions, 3198 deletions
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 9f38c5833a2..7cbaf6bdad2 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -28,13 +28,13 @@
#ifndef BKE_CONTEXT_H
#define BKE_CONTEXT_H
+#include "DNA_listBase.h"
+#include "RNA_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_listBase.h"
-#include "RNA_types.h"
-
struct ARegion;
struct bScreen;
struct EditMesh;
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
index 0b78a1206fe..5b2dca5299c 100644
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -28,6 +28,10 @@
#ifndef DEPSGRAPH_API
#define DEPSGRAPH_API
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
#define DEPS_DEBUG
*/
@@ -120,5 +124,9 @@ void DAG_pose_sort(struct Object *ob);
/* callback for editors module to do updates */
void DAG_editors_update_cb(void (*func)(struct Main *bmain, struct ID *id));
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 95e0cfc3a91..8dbfb4f2c73 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -28,6 +28,10 @@
#ifndef BKE_FCURVE_H
#define BKE_FCURVE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct FCurve;
struct FModifier;
struct ChannelDriver;
@@ -248,4 +252,8 @@ float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime
*/
void fcurve_store_samples(struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* BKE_FCURVE_H*/
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index e25c379ded1..b74de66f7b6 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -33,6 +33,10 @@
#ifndef BKE_LIBRARY_TYPES_H
#define BKE_LIBRARY_TYPES_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ListBase;
struct ID;
struct Main;
@@ -85,4 +89,8 @@ void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowMa
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME "Untitled"
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 60c2d51571f..1a53f488841 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -40,6 +40,10 @@
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Library;
typedef struct Main {
@@ -80,5 +84,9 @@ typedef struct Main {
} Main;
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 96ef8d44cf4..8d5ebb64cf0 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -31,6 +31,10 @@
#ifndef BKE_SCENE_H
#define BKE_SCENE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AviCodecData;
struct Base;
struct bglMats;
@@ -93,5 +97,9 @@ int get_render_child_particle_number(struct RenderData *r, int num);
int get_render_shadow_samples(struct RenderData *r, int samples);
float get_render_aosss_error(struct RenderData *r, float error);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 99bb8db44ed..cbae90f4c38 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -31,6 +31,10 @@
#ifndef BKE_TEXTURE_H
#define BKE_TEXTURE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bNode;
struct Brush;
struct ColorBand;
@@ -112,5 +116,9 @@ struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd);
int BKE_texture_dependsOnTime(const struct Tex *texture);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
new file mode 100644
index 00000000000..92e863db023
--- /dev/null
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -0,0 +1,1149 @@
+/**
+ * $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 "DNA_armature_types.h"
+
+#include "ED_keyframing.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_fcurve.h"
+#include "BKE_object.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "collada_utils.h"
+#include "AnimationImporter.h"
+#include "ArmatureImporter.h"
+
+#include <algorithm>
+
+// 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();
+}
+
+FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path)
+{
+ FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
+
+ fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
+ fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+ fcu->array_index = array_index;
+ return fcu;
+}
+
+void AnimationImporter::create_bezt(FCurve *fcu, float frame, float output)
+{
+ BezTriple bez;
+ memset(&bez, 0, sizeof(BezTriple));
+ bez.vec[1][0] = frame;
+ bez.vec[1][1] = output;
+ bez.ipo = U.ipo_new; /* use default interpolation mode here... */
+ bez.f1 = bez.f2 = bez.f3 = SELECT;
+ bez.h1 = bez.h2 = HD_AUTO;
+ insert_bezt_fcurve(fcu, &bez, 0);
+ calchandles_fcurve(fcu);
+}
+
+// create one or several fcurves depending on the number of parameters being animated
+void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
+{
+ COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues();
+ COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues();
+ // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues();
+ // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues();
+ float fps = (float)FPS;
+ size_t dim = curve->getOutDimension();
+ unsigned int i;
+
+ std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()];
+
+ switch (dim) {
+ case 1: // X, Y, Z or angle
+ case 3: // XYZ
+ case 16: // matrix
+ {
+ for (i = 0; i < dim; i++ ) {
+ FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
+
+ fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
+ // fcu->rna_path = BLI_strdupn(path, strlen(path));
+ fcu->array_index = 0;
+ //fcu->totvert = curve->getKeyCount();
+
+ // create beztriple for each key
+ for (unsigned int j = 0; j < curve->getKeyCount(); j++) {
+ BezTriple bez;
+ memset(&bez, 0, sizeof(BezTriple));
+
+ // intangent
+ // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps;
+ // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1);
+
+ // input, output
+ bez.vec[1][0] = bc_get_float_value(input, j) * fps;
+ bez.vec[1][1] = bc_get_float_value(output, j * dim + i);
+
+ // outtangent
+ // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps;
+ // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1);
+
+ bez.ipo = U.ipo_new; /* use default interpolation mode here... */
+ bez.f1 = bez.f2 = bez.f3 = SELECT;
+ bez.h1 = bez.h2 = HD_AUTO;
+ insert_bezt_fcurve(fcu, &bez, 0);
+ }
+
+ calchandles_fcurve(fcu);
+
+ fcurves.push_back(fcu);
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "Output dimension of %d is not yet supported (animation id = %s)\n", dim, curve->getOriginalId().c_str());
+ }
+
+ for (std::vector<FCurve*>::iterator it = fcurves.begin(); it != fcurves.end(); it++)
+ unused_curves.push_back(*it);
+}
+
+void AnimationImporter::fcurve_deg_to_rad(FCurve *cu)
+{
+ for (unsigned int i = 0; i < cu->totvert; i++) {
+ // TODO convert handles too
+ cu->bezt[i].vec[1][1] *= M_PI / 180.0f;
+ }
+}
+
+void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated)
+{
+ bAction *act;
+
+ if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1);
+ else act = ob->adt->action;
+
+ std::vector<FCurve*>::iterator it;
+ int i;
+
+#if 0
+ char *p = strstr(rna_path, "rotation_euler");
+ bool is_rotation = p && *(p + strlen("rotation_euler")) == '\0';
+
+ // convert degrees to radians for rotation
+ if (is_rotation)
+ fcurve_deg_to_rad(fcu);
+#endif
+
+ for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) {
+ FCurve *fcu = *it;
+ fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+
+ if (array_index == -1) fcu->array_index = i;
+ else fcu->array_index = array_index;
+
+ if (ob->type == OB_ARMATURE) {
+ bActionGroup *grp = NULL;
+ const char *bone_name = bc_get_joint_name(animated->node);
+
+ if (bone_name) {
+ /* try to find group */
+ grp = action_groups_find_named(act, bone_name);
+
+ /* no matching groups, so add one */
+ if (grp == NULL) {
+ /* Add a new group, and make it active */
+ grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+
+ grp->flag = AGRP_SELECTED;
+ BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
+
+ BLI_addtail(&act->groups, grp);
+ BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
+ }
+
+ /* add F-Curve to group */
+ action_groups_add_channel(act, grp, fcu);
+
+ }
+#if 0
+ if (is_rotation) {
+ fcurves_actionGroup_map[grp].push_back(fcu);
+ }
+#endif
+ }
+ else {
+ BLI_addtail(&act->curves, fcu);
+ }
+
+ // curve is used, so remove it from unused_curves
+ unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end());
+ }
+}
+
+AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
+ TransformReader(conv), armature_importer(arm), scene(scene) { }
+
+AnimationImporter::~AnimationImporter()
+{
+ // free unused FCurves
+ for (std::vector<FCurve*>::iterator it = unused_curves.begin(); it != unused_curves.end(); it++)
+ free_fcurve(*it);
+
+ if (unused_curves.size())
+ fprintf(stderr, "removed %u unused curves\n", unused_curves.size());
+}
+
+bool AnimationImporter::write_animation(const COLLADAFW::Animation* anim)
+{
+ if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
+ COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim;
+
+ // XXX Don't know if it's necessary
+ // Should we check outPhysicalDimension?
+ if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) {
+ fprintf(stderr, "Inputs physical dimension is not time. \n");
+ return true;
+ }
+
+ // a curve can have mixed interpolation type,
+ // in this case curve->getInterpolationTypes returns a list of interpolation types per key
+ COLLADAFW::AnimationCurve::InterpolationType interp = curve->getInterpolationType();
+
+ if (interp != COLLADAFW::AnimationCurve::INTERPOLATION_MIXED) {
+ switch (interp) {
+ case COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR:
+ case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER:
+ animation_to_fcurves(curve);
+ break;
+ default:
+ // TODO there're also CARDINAL, HERMITE, BSPLINE and STEP types
+ fprintf(stderr, "CARDINAL, HERMITE, BSPLINE and STEP anim interpolation types not supported yet.\n");
+ break;
+ }
+ }
+ else {
+ // not supported yet
+ fprintf(stderr, "MIXED anim interpolation type is not supported yet.\n");
+ }
+ }
+ else {
+ fprintf(stderr, "FORMULA animation type is not supported yet.\n");
+ }
+
+ return true;
+}
+
+// called on post-process stage after writeVisualScenes
+bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList* animlist)
+{
+ const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId();
+
+ animlist_map[animlist_id] = animlist;
+
+#if 0
+ // should not happen
+ if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) {
+ return true;
+ }
+
+ // for bones rna_path is like: pose.bones["bone-name"].rotation
+
+ // what does this AnimationList animate?
+ Animation& animated = uid_animated_map[animlist_id];
+ Object *ob = animated.ob;
+
+ char rna_path[100];
+ char joint_path[100];
+ bool is_joint = false;
+
+ // if ob is NULL, it should be a JOINT
+ if (!ob) {
+ ob = armature_importer->get_armature_for_joint(animated.node);
+
+ if (!ob) {
+ fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node));
+ return true;
+ }
+
+ armature_importer->get_rna_path_for_joint(animated.node, joint_path, sizeof(joint_path));
+
+ is_joint = true;
+ }
+
+ const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
+
+ switch (animated.tm->getTransformationType()) {
+ case COLLADAFW::Transformation::TRANSLATE:
+ case COLLADAFW::Transformation::SCALE:
+ {
+ bool loc = animated.tm->getTransformationType() == COLLADAFW::Transformation::TRANSLATE;
+ if (is_joint)
+ BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale");
+ else
+ BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path));
+
+ for (int i = 0; i < bindings.getCount(); i++) {
+ const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
+ COLLADAFW::UniqueId anim_uid = binding.animation;
+
+ if (curve_map.find(anim_uid) == curve_map.end()) {
+ fprintf(stderr, "Cannot find FCurve by animation UID.\n");
+ continue;
+ }
+
+ std::vector<FCurve*>& fcurves = curve_map[anim_uid];
+
+ switch (binding.animationClass) {
+ case COLLADAFW::AnimationList::POSITION_X:
+ add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
+ break;
+ case COLLADAFW::AnimationList::POSITION_Y:
+ add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
+ break;
+ case COLLADAFW::AnimationList::POSITION_Z:
+ add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
+ break;
+ case COLLADAFW::AnimationList::POSITION_XYZ:
+ add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated);
+ break;
+ default:
+ fprintf(stderr, "AnimationClass %d is not supported for %s.\n",
+ binding.animationClass, loc ? "TRANSLATE" : "SCALE");
+ }
+ }
+ }
+ break;
+ case COLLADAFW::Transformation::ROTATE:
+ {
+ if (is_joint)
+ BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path);
+ else
+ BLI_strncpy(rna_path, "rotation_euler", sizeof(rna_path));
+
+ COLLADAFW::Rotate* rot = (COLLADAFW::Rotate*)animated.tm;
+ COLLADABU::Math::Vector3& axis = rot->getRotationAxis();
+
+ for (int i = 0; i < bindings.getCount(); i++) {
+ const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
+ COLLADAFW::UniqueId anim_uid = binding.animation;
+
+ if (curve_map.find(anim_uid) == curve_map.end()) {
+ fprintf(stderr, "Cannot find FCurve by animation UID.\n");
+ continue;
+ }
+
+ std::vector<FCurve*>& fcurves = curve_map[anim_uid];
+
+ switch (binding.animationClass) {
+ case COLLADAFW::AnimationList::ANGLE:
+ if (COLLADABU::Math::Vector3::UNIT_X == axis) {
+ add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
+ }
+ else if (COLLADABU::Math::Vector3::UNIT_Y == axis) {
+ add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
+ }
+ else if (COLLADABU::Math::Vector3::UNIT_Z == axis) {
+ add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
+ }
+ break;
+ case COLLADAFW::AnimationList::AXISANGLE:
+ // TODO convert axis-angle to quat? or XYZ?
+ default:
+ fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n",
+ binding.animationClass);
+ }
+ }
+ }
+ break;
+ case COLLADAFW::Transformation::MATRIX:
+ case COLLADAFW::Transformation::SKEW:
+ case COLLADAFW::Transformation::LOOKAT:
+ fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n");
+ break;
+ }
+#endif
+
+ return true;
+}
+
+void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob)
+{
+ float mat[4][4];
+ TransformReader::get_node_mat(mat, node, &uid_animated_map, ob);
+ if (ob) {
+ copy_m4_m4(ob->obmat, mat);
+ object_apply_mat4(ob, ob->obmat);
+ }
+}
+
+#if 0
+virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
+{
+ bActionGroup *grp;
+ int i;
+
+ for (grp = (bActionGroup*)act->groups.first; grp; grp = grp->next) {
+
+ FCurve *eulcu[3] = {NULL, NULL, NULL};
+
+ if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end())
+ continue;
+
+ std::vector<FCurve*> &rot_fcurves = fcurves_actionGroup_map[grp];
+
+ if (rot_fcurves.size() > 3) continue;
+
+ for (i = 0; i < rot_fcurves.size(); i++)
+ eulcu[rot_fcurves[i]->array_index] = rot_fcurves[i];
+
+ char joint_path[100];
+ char rna_path[100];
+
+ BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name);
+ BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path);
+
+ FCurve *quatcu[4] = {
+ create_fcurve(0, rna_path),
+ create_fcurve(1, rna_path),
+ create_fcurve(2, rna_path),
+ create_fcurve(3, rna_path)
+ };
+
+ bPoseChannel *chan = get_pose_channel(ob->pose, grp->name);
+
+ float m4[4][4], irest[3][3];
+ invert_m4_m4(m4, chan->bone->arm_mat);
+ copy_m3_m4(irest, m4);
+
+ for (i = 0; i < 3; i++) {
+
+ FCurve *cu = eulcu[i];
+
+ if (!cu) continue;
+
+ for (int j = 0; j < cu->totvert; j++) {
+ float frame = cu->bezt[j].vec[1][0];
+
+ float eul[3] = {
+ eulcu[0] ? evaluate_fcurve(eulcu[0], frame) : 0.0f,
+ eulcu[1] ? evaluate_fcurve(eulcu[1], frame) : 0.0f,
+ eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f
+ };
+
+ // make eul relative to bone rest pose
+ float rot[3][3], rel[3][3], quat[4];
+
+ /*eul_to_mat3(rot, eul);
+
+ mul_m3_m3m3(rel, irest, rot);
+
+ mat3_to_quat(quat, rel);
+ */
+
+ eul_to_quat(quat, eul);
+
+ for (int k = 0; k < 4; k++)
+ create_bezt(quatcu[k], frame, quat[k]);
+ }
+ }
+
+ // now replace old Euler curves
+
+ for (i = 0; i < 3; i++) {
+ if (!eulcu[i]) continue;
+
+ action_groups_remove_channel(act, eulcu[i]);
+ free_fcurve(eulcu[i]);
+ }
+
+ chan->rotmode = ROT_MODE_QUAT;
+
+ for (i = 0; i < 4; i++)
+ action_groups_add_channel(act, grp, quatcu[i]);
+ }
+
+ bPoseChannel *pchan;
+ for (pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->rotmode = ROT_MODE_QUAT;
+ }
+}
+#endif
+
+// prerequisites:
+// animlist_map - map animlist id -> animlist
+// curve_map - map anim id -> curve(s)
+Object *AnimationImporter::translate_animation(COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Object*>& object_map,
+ std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
+ COLLADAFW::Transformation::TransformationType tm_type,
+ Object *par_job)
+{
+ bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE;
+ bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX;
+ bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
+
+ COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()];
+ Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()];
+ const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL;
+
+ if (!ob) {
+ fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str());
+ return NULL;
+ }
+
+ // frames at which to sample
+ std::vector<float> frames;
+
+ // for each <rotate>, <translate>, etc. there is a separate Transformation
+ const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
+
+ unsigned int i;
+
+ // find frames at which to sample plus convert all rotation keys to radians
+ for (i = 0; i < tms.getCount(); i++) {
+ COLLADAFW::Transformation *tm = tms[i];
+ COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
+
+ if (type == tm_type) {
+ const COLLADAFW::UniqueId& listid = tm->getAnimationList();
+
+ if (animlist_map.find(listid) != animlist_map.end()) {
+ const COLLADAFW::AnimationList *animlist = animlist_map[listid];
+ const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
+
+ if (bindings.getCount()) {
+ for (unsigned int j = 0; j < bindings.getCount(); j++) {
+ std::vector<FCurve*>& curves = curve_map[bindings[j].animation];
+ bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ);
+
+ if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3) || is_matrix) {
+ std::vector<FCurve*>::iterator iter;
+
+ for (iter = curves.begin(); iter != curves.end(); iter++) {
+ FCurve *fcu = *iter;
+
+ if (is_rotation)
+ fcurve_deg_to_rad(fcu);
+
+ for (unsigned int k = 0; k < fcu->totvert; k++) {
+ float fra = fcu->bezt[k].vec[1][0];
+ if (std::find(frames.begin(), frames.end(), fra) == frames.end())
+ frames.push_back(fra);
+ }
+ }
+ }
+ else {
+ fprintf(stderr, "expected %d curves, got %u\n", xyz ? 3 : 1, curves.size());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ float irest_dae[4][4];
+ float rest[4][4], irest[4][4];
+
+ if (is_joint) {
+ get_joint_rest_mat(irest_dae, root, node);
+ invert_m4(irest_dae);
+
+ Bone *bone = get_named_bone((bArmature*)ob->data, bone_name);
+ if (!bone) {
+ fprintf(stderr, "cannot find bone \"%s\"\n", bone_name);
+ return NULL;
+ }
+
+ unit_m4(rest);
+ copy_m4_m4(rest, bone->arm_mat);
+ invert_m4_m4(irest, rest);
+ }
+
+ Object *job = NULL;
+
+#ifdef ARMATURE_TEST
+ FCurve *job_curves[10];
+ job = get_joint_object(root, node, par_job);
+#endif
+
+ if (frames.size() == 0)
+ return job;
+
+ std::sort(frames.begin(), frames.end());
+
+ const char *tm_str = NULL;
+ switch (tm_type) {
+ case COLLADAFW::Transformation::ROTATE:
+ tm_str = "rotation_quaternion";
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ tm_str = "scale";
+ break;
+ case COLLADAFW::Transformation::TRANSLATE:
+ tm_str = "location";
+ break;
+ case COLLADAFW::Transformation::MATRIX:
+ break;
+ default:
+ return job;
+ }
+
+ char rna_path[200];
+ char joint_path[200];
+
+ if (is_joint)
+ armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
+
+ // new curves
+ FCurve *newcu[10]; // if tm_type is matrix, then create 10 curves: 4 rot, 3 loc, 3 scale
+ unsigned int totcu = is_matrix ? 10 : (is_rotation ? 4 : 3);
+
+ for (i = 0; i < totcu; i++) {
+
+ int axis = i;
+
+ if (is_matrix) {
+ if (i < 4) {
+ tm_str = "rotation_quaternion";
+ axis = i;
+ }
+ else if (i < 7) {
+ tm_str = "location";
+ axis = i - 4;
+ }
+ else {
+ tm_str = "scale";
+ axis = i - 7;
+ }
+ }
+
+ if (is_joint)
+ BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str);
+ else
+ strcpy(rna_path, tm_str);
+
+ newcu[i] = create_fcurve(axis, rna_path);
+
+#ifdef ARMATURE_TEST
+ if (is_joint)
+ job_curves[i] = create_fcurve(axis, tm_str);
+#endif
+ }
+
+ std::vector<float>::iterator it;
+
+ // sample values at each frame
+ for (it = frames.begin(); it != frames.end(); it++) {
+ float fra = *it;
+
+ float mat[4][4];
+ float matfra[4][4];
+
+ unit_m4(matfra);
+
+ // calc object-space mat
+ evaluate_transform_at_frame(matfra, node, fra);
+
+ // for joints, we need a special matrix
+ if (is_joint) {
+ // special matrix: iR * M * iR_dae * R
+ // where R, iR are bone rest and inverse rest mats in world space (Blender bones),
+ // iR_dae is joint inverse rest matrix (DAE) and M is an evaluated joint world-space matrix (DAE)
+ float temp[4][4], par[4][4];
+
+ // calc M
+ calc_joint_parent_mat_rest(par, NULL, root, node);
+ mul_m4_m4m4(temp, matfra, par);
+
+ // evaluate_joint_world_transform_at_frame(temp, NULL, , node, fra);
+
+ // calc special matrix
+ mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL);
+ }
+ else {
+ copy_m4_m4(mat, matfra);
+ }
+
+ float val[4], rot[4], loc[3], scale[3];
+
+ switch (tm_type) {
+ case COLLADAFW::Transformation::ROTATE:
+ mat4_to_quat(val, mat);
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ mat4_to_size(val, mat);
+ break;
+ case COLLADAFW::Transformation::TRANSLATE:
+ copy_v3_v3(val, mat[3]);
+ break;
+ case COLLADAFW::Transformation::MATRIX:
+ mat4_to_quat(rot, mat);
+ copy_v3_v3(loc, mat[3]);
+ mat4_to_size(scale, mat);
+ break;
+ default:
+ break;
+ }
+
+ // add keys
+ for (i = 0; i < totcu; i++) {
+ if (is_matrix) {
+ if (i < 4)
+ add_bezt(newcu[i], fra, rot[i]);
+ else if (i < 7)
+ add_bezt(newcu[i], fra, loc[i - 4]);
+ else
+ add_bezt(newcu[i], fra, scale[i - 7]);
+ }
+ else {
+ add_bezt(newcu[i], fra, val[i]);
+ }
+ }
+
+#ifdef ARMATURE_TEST
+ if (is_joint) {
+ switch (tm_type) {
+ case COLLADAFW::Transformation::ROTATE:
+ mat4_to_quat(val, matfra);
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ mat4_to_size(val, matfra);
+ break;
+ case COLLADAFW::Transformation::TRANSLATE:
+ copy_v3_v3(val, matfra[3]);
+ break;
+ case MATRIX:
+ mat4_to_quat(rot, matfra);
+ copy_v3_v3(loc, matfra[3]);
+ mat4_to_size(scale, matfra);
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < totcu; i++) {
+ if (is_matrix) {
+ if (i < 4)
+ add_bezt(job_curves[i], fra, rot[i]);
+ else if (i < 7)
+ add_bezt(job_curves[i], fra, loc[i - 4]);
+ else
+ add_bezt(job_curves[i], fra, scale[i - 7]);
+ }
+ else {
+ add_bezt(job_curves[i], fra, val[i]);
+ }
+ }
+ }
+#endif
+ }
+
+ verify_adt_action((ID*)&ob->id, 1);
+
+ ListBase *curves = &ob->adt->action->curves;
+
+ // add curves
+ for (i = 0; i < totcu; i++) {
+ if (is_joint)
+ add_bone_fcurve(ob, node, newcu[i]);
+ else
+ BLI_addtail(curves, newcu[i]);
+
+#ifdef ARMATURE_TEST
+ if (is_joint)
+ BLI_addtail(&job->adt->action->curves, job_curves[i]);
+#endif
+ }
+
+ if (is_rotation || is_matrix) {
+ if (is_joint) {
+ bPoseChannel *chan = get_pose_channel(ob->pose, bone_name);
+ chan->rotmode = ROT_MODE_QUAT;
+ }
+ else {
+ ob->rotmode = ROT_MODE_QUAT;
+ }
+ }
+
+ return job;
+}
+
+// internal, better make it private
+// warning: evaluates only rotation
+// prerequisites: animlist_map, curve_map
+void AnimationImporter::evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra)
+{
+ const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
+
+ unit_m4(mat);
+
+ for (unsigned int i = 0; i < tms.getCount(); i++) {
+ COLLADAFW::Transformation *tm = tms[i];
+ COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
+ float m[4][4];
+
+ unit_m4(m);
+
+ if (!evaluate_animation(tm, m, fra, node->getOriginalId().c_str())) {
+ switch (type) {
+ case COLLADAFW::Transformation::ROTATE:
+ dae_rotate_to_mat4(tm, m);
+ break;
+ case COLLADAFW::Transformation::TRANSLATE:
+ dae_translate_to_mat4(tm, m);
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ dae_scale_to_mat4(tm, m);
+ break;
+ case COLLADAFW::Transformation::MATRIX:
+ dae_matrix_to_mat4(tm, m);
+ break;
+ default:
+ fprintf(stderr, "unsupported transformation type %d\n", type);
+ }
+ }
+
+ float temp[4][4];
+ copy_m4_m4(temp, mat);
+
+ mul_m4_m4m4(mat, m, temp);
+ }
+}
+
+// return true to indicate that mat contains a sane value
+bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id)
+{
+ const COLLADAFW::UniqueId& listid = tm->getAnimationList();
+ COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
+
+ if (type != COLLADAFW::Transformation::ROTATE &&
+ type != COLLADAFW::Transformation::SCALE &&
+ type != COLLADAFW::Transformation::TRANSLATE &&
+ type != COLLADAFW::Transformation::MATRIX) {
+ fprintf(stderr, "animation of transformation %d is not supported yet\n", type);
+ return false;
+ }
+
+ if (animlist_map.find(listid) == animlist_map.end())
+ return false;
+
+ const COLLADAFW::AnimationList *animlist = animlist_map[listid];
+ const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
+
+ if (bindings.getCount()) {
+ float vec[3];
+
+ bool is_scale = (type == COLLADAFW::Transformation::SCALE);
+ bool is_translate = (type == COLLADAFW::Transformation::TRANSLATE);
+
+ if (type == COLLADAFW::Transformation::SCALE)
+ dae_scale_to_v3(tm, vec);
+ else if (type == COLLADAFW::Transformation::TRANSLATE)
+ dae_translate_to_v3(tm, vec);
+
+ for (unsigned int j = 0; j < bindings.getCount(); j++) {
+ const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j];
+ std::vector<FCurve*>& curves = curve_map[binding.animation];
+ COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass;
+ char path[100];
+
+ switch (type) {
+ case COLLADAFW::Transformation::ROTATE:
+ BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j);
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j);
+ break;
+ case COLLADAFW::Transformation::TRANSLATE:
+ BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j);
+ break;
+ case COLLADAFW::Transformation::MATRIX:
+ BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j);
+ break;
+ default:
+ break;
+ }
+
+ if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) {
+ fprintf(stderr, "%s: UNKNOWN animation class\n", path);
+ continue;
+ }
+
+ if (type == COLLADAFW::Transformation::ROTATE) {
+ if (curves.size() != 1) {
+ fprintf(stderr, "expected 1 curve, got %u\n", curves.size());
+ return false;
+ }
+
+ // TODO support other animclasses
+ if (animclass != COLLADAFW::AnimationList::ANGLE) {
+ fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass);
+ return false;
+ }
+
+ COLLADABU::Math::Vector3& axis = ((COLLADAFW::Rotate*)tm)->getRotationAxis();
+ float ax[3] = {axis[0], axis[1], axis[2]};
+ float angle = evaluate_fcurve(curves[0], fra);
+ axis_angle_to_mat4(mat, ax, angle);
+
+ return true;
+ }
+ else if (is_scale || is_translate) {
+ bool is_xyz = animclass == COLLADAFW::AnimationList::POSITION_XYZ;
+
+ if ((!is_xyz && curves.size() != 1) || (is_xyz && curves.size() != 3)) {
+ if (is_xyz)
+ fprintf(stderr, "%s: expected 3 curves, got %u\n", path, curves.size());
+ else
+ fprintf(stderr, "%s: expected 1 curve, got %u\n", path, curves.size());
+ return false;
+ }
+
+ switch (animclass) {
+ case COLLADAFW::AnimationList::POSITION_X:
+ vec[0] = evaluate_fcurve(curves[0], fra);
+ break;
+ case COLLADAFW::AnimationList::POSITION_Y:
+ vec[1] = evaluate_fcurve(curves[0], fra);
+ break;
+ case COLLADAFW::AnimationList::POSITION_Z:
+ vec[2] = evaluate_fcurve(curves[0], fra);
+ break;
+ case COLLADAFW::AnimationList::POSITION_XYZ:
+ vec[0] = evaluate_fcurve(curves[0], fra);
+ vec[1] = evaluate_fcurve(curves[1], fra);
+ vec[2] = evaluate_fcurve(curves[2], fra);
+ break;
+ default:
+ fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass);
+ break;
+ }
+ }
+ else if (type == COLLADAFW::Transformation::MATRIX) {
+ // for now, of matrix animation, support only the case when all values are packed into one animation
+ if (curves.size() != 16) {
+ fprintf(stderr, "%s: expected 16 curves, got %u\n", path, curves.size());
+ return false;
+ }
+
+ COLLADABU::Math::Matrix4 matrix;
+ int i = 0, j = 0;
+
+ for (std::vector<FCurve*>::iterator it = curves.begin(); it != curves.end(); it++) {
+ matrix.setElement(i, j, evaluate_fcurve(*it, fra));
+ j++;
+ if (j == 4) {
+ i++;
+ j = 0;
+ }
+ }
+
+ COLLADAFW::Matrix tm(matrix);
+ dae_matrix_to_mat4(&tm, mat);
+
+ return true;
+ }
+ }
+
+ if (is_scale)
+ size_to_mat4(mat, vec);
+ else
+ copy_v3_v3(mat[3], vec);
+
+ return is_scale || is_translate;
+ }
+
+ return false;
+}
+
+// gives a world-space mat of joint at rest position
+void AnimationImporter::get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node)
+{
+ // if bind mat is not available,
+ // use "current" node transform, i.e. all those tms listed inside <node>
+ if (!armature_importer->get_joint_bind_mat(mat, node)) {
+ float par[4][4], m[4][4];
+
+ calc_joint_parent_mat_rest(par, NULL, root, node);
+ get_node_mat(m, node, NULL, NULL);
+ mul_m4_m4m4(mat, m, par);
+ }
+}
+
+// gives a world-space mat, end's mat not included
+bool AnimationImporter::calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end)
+{
+ float m[4][4];
+
+ if (node == end) {
+ par ? copy_m4_m4(mat, par) : unit_m4(mat);
+ return true;
+ }
+
+ // use bind matrix if available or calc "current" world mat
+ if (!armature_importer->get_joint_bind_mat(m, node)) {
+ if (par) {
+ float temp[4][4];
+ get_node_mat(temp, node, NULL, NULL);
+ mul_m4_m4m4(m, temp, par);
+ }
+ else {
+ get_node_mat(m, node, NULL, NULL);
+ }
+ }
+
+ COLLADAFW::NodePointerArray& children = node->getChildNodes();
+ for (unsigned int i = 0; i < children.getCount(); i++) {
+ if (calc_joint_parent_mat_rest(mat, m, children[i], end))
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef ARMATURE_TEST
+Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job)
+{
+ if (joint_objects.find(node->getUniqueId()) == joint_objects.end()) {
+ Object *job = add_object(scene, OB_EMPTY);
+
+ rename_id((ID*)&job->id, (char*)get_joint_name(node));
+
+ job->lay = object_in_scene(job, scene)->lay = 2;
+
+ mul_v3_fl(job->size, 0.5f);
+ job->recalc |= OB_RECALC_OB;
+
+ verify_adt_action((ID*)&job->id, 1);
+
+ job->rotmode = ROT_MODE_QUAT;
+
+ float mat[4][4];
+ get_joint_rest_mat(mat, root, node);
+
+ if (par_job) {
+ float temp[4][4], ipar[4][4];
+ invert_m4_m4(ipar, par_job->obmat);
+ copy_m4_m4(temp, mat);
+ mul_m4_m4m4(mat, temp, ipar);
+ }
+
+ TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size);
+
+ if (par_job) {
+ job->parent = par_job;
+
+ par_job->recalc |= OB_RECALC_OB;
+ job->parsubstr[0] = 0;
+ }
+
+ where_is_object(scene, job);
+
+ // after parenting and layer change
+ DAG_scene_sort(CTX_data_main(C), scene);
+
+ joint_objects[node->getUniqueId()] = job;
+ }
+
+ return joint_objects[node->getUniqueId()];
+}
+#endif
+
+#if 0
+// recursively evaluates joint tree until end is found, mat then is world-space matrix of end
+// mat must be identity on enter, node must be root
+bool AnimationImporter::evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra)
+{
+ float m[4][4];
+ if (par) {
+ float temp[4][4];
+ evaluate_transform_at_frame(temp, node, node == end ? fra : 0.0f);
+ mul_m4_m4m4(m, temp, par);
+ }
+ else {
+ evaluate_transform_at_frame(m, node, node == end ? fra : 0.0f);
+ }
+
+ if (node == end) {
+ copy_m4_m4(mat, m);
+ return true;
+ }
+ else {
+ COLLADAFW::NodePointerArray& children = node->getChildNodes();
+ for (int i = 0; i < children.getCount(); i++) {
+ if (evaluate_joint_world_transform_at_frame(mat, m, children[i], end, fra))
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
+void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu)
+{
+ const char *bone_name = bc_get_joint_name(node);
+ bAction *act = ob->adt->action;
+
+ /* try to find group */
+ bActionGroup *grp = action_groups_find_named(act, bone_name);
+
+ /* no matching groups, so add one */
+ if (grp == NULL) {
+ /* Add a new group, and make it active */
+ grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+
+ grp->flag = AGRP_SELECTED;
+ BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
+
+ BLI_addtail(&act->groups, grp);
+ BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
+ }
+
+ /* add F-Curve to group */
+ action_groups_add_channel(act, grp, fcu);
+}
+
+void AnimationImporter::add_bezt(FCurve *fcu, float fra, float value)
+{
+ BezTriple bez;
+ memset(&bez, 0, sizeof(BezTriple));
+ bez.vec[1][0] = fra;
+ bez.vec[1][1] = value;
+ bez.ipo = U.ipo_new; /* use default interpolation mode here... */
+ bez.f1 = bez.f2 = bez.f3 = SELECT;
+ bez.h1 = bez.h2 = HD_AUTO;
+ insert_bezt_fcurve(fcu, &bez, 0);
+ calchandles_fcurve(fcu);
+}
diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h
new file mode 100644
index 00000000000..9854a9d2663
--- /dev/null
+++ b/source/blender/collada/AnimationImporter.h
@@ -0,0 +1,132 @@
+/**
+ * $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 *****
+ */
+
+#ifndef __BC_ANIMATIONIMPORTER_H__
+#define __BC_ANIMATIONIMPORTER_H__
+
+#include <map>
+#include <vector>
+
+#include "COLLADAFWAnimation.h"
+#include "COLLADAFWAnimationCurve.h"
+#include "COLLADAFWAnimationList.h"
+#include "COLLADAFWNode.h"
+#include "COLLADAFWUniqueId.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+//#include "ArmatureImporter.h"
+#include "TransformReader.h"
+
+#include "collada_internal.h"
+
+class ArmatureImporter;
+
+class AnimationImporterBase
+{
+public:
+ // virtual void change_eul_to_quat(Object *ob, bAction *act) = 0;
+};
+
+class AnimationImporter : private TransformReader, public AnimationImporterBase
+{
+private:
+
+ ArmatureImporter *armature_importer;
+ Scene *scene;
+
+ std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > curve_map;
+ std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map;
+ // std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map;
+ std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map;
+ std::vector<FCurve*> unused_curves;
+ std::map<COLLADAFW::UniqueId, Object*> joint_objects;
+
+ FCurve *create_fcurve(int array_index, const char *rna_path);
+
+ void create_bezt(FCurve *fcu, float frame, float output);
+
+ // create one or several fcurves depending on the number of parameters being animated
+ void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
+
+ void fcurve_deg_to_rad(FCurve *cu);
+
+ void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated);
+public:
+
+ AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene);
+
+ ~AnimationImporter();
+
+ bool write_animation(const COLLADAFW::Animation* anim);
+
+ // called on post-process stage after writeVisualScenes
+ bool write_animation_list(const COLLADAFW::AnimationList* animlist);
+
+ void read_node_transform(COLLADAFW::Node *node, Object *ob);
+#if 0
+ virtual void change_eul_to_quat(Object *ob, bAction *act);
+#endif
+
+ // prerequisites:
+ // animlist_map - map animlist id -> animlist
+ // curve_map - map anim id -> curve(s)
+ Object *translate_animation(COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Object*>& object_map,
+ std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
+ COLLADAFW::Transformation::TransformationType tm_type,
+ Object *par_job = NULL);
+
+ // internal, better make it private
+ // warning: evaluates only rotation
+ // prerequisites: animlist_map, curve_map
+ void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra);
+
+ // return true to indicate that mat contains a sane value
+ bool evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id);
+
+ // gives a world-space mat of joint at rest position
+ void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node);
+
+ // gives a world-space mat, end's mat not included
+ bool calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end);
+
+#ifdef ARMATURE_TEST
+ Object *get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job);
+#endif
+
+#if 0
+ // recursively evaluates joint tree until end is found, mat then is world-space matrix of end
+ // mat must be identity on enter, node must be root
+ bool evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra);
+#endif
+
+ void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu);
+
+ void add_bezt(FCurve *fcu, float fra, float value);
+};
+
+ #endif \ No newline at end of file
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
new file mode 100644
index 00000000000..f931c04aef1
--- /dev/null
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -0,0 +1,585 @@
+/**
+ * $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 "COLLADAFWUniqueId.h"
+
+#include "BKE_action.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+#include "BLI_string.h"
+#include "ED_armature.h"
+
+#include "ArmatureImporter.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();
+}
+
+ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce) :
+ TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh), anim_importer(anim) {}
+
+ArmatureImporter::~ArmatureImporter()
+{
+ // free skin controller data if we forget to do this earlier
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+ for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+ it->second.free();
+ }
+}
+
+#if 0
+JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node);
+{
+ const COLLADAFW::UniqueId& joint_id = node->getUniqueId();
+
+ if (joint_id_to_joint_index_map.find(joint_id) == joint_id_to_joint_index_map.end()) {
+ fprintf(stderr, "Cannot find a joint index by joint id for %s.\n",
+ node->getOriginalId().c_str());
+ return NULL;
+ }
+
+ int joint_index = joint_id_to_joint_index_map[joint_id];
+
+ return &joint_index_to_joint_info_map[joint_index];
+}
+#endif
+
+void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
+ float parent_mat[][4], bArmature *arm)
+{
+ float joint_inv_bind_mat[4][4];
+
+ // JointData* jd = get_joint_data(node);
+
+ float mat[4][4];
+
+ if (skin.get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
+ // get original world-space matrix
+ invert_m4_m4(mat, joint_inv_bind_mat);
+ }
+ // create a bone even if there's no joint data for it (i.e. it has no influence)
+ else {
+ float obmat[4][4];
+
+ // object-space
+ get_node_mat(obmat, node, NULL, NULL);
+
+ // get world-space
+ if (parent)
+ mul_m4_m4m4(mat, obmat, parent_mat);
+ else
+ copy_m4_m4(mat, obmat);
+ }
+
+ // TODO rename from Node "name" attrs later
+ EditBone *bone = ED_armature_edit_bone_add(arm, (char*)bc_get_joint_name(node));
+ totbone++;
+
+ if (parent) bone->parent = parent;
+
+ // set head
+ copy_v3_v3(bone->head, mat[3]);
+
+ // set tail, don't set it to head because 0-length bones are not allowed
+ float vec[3] = {0.0f, 0.5f, 0.0f};
+ add_v3_v3v3(bone->tail, bone->head, vec);
+
+ // set parent tail
+ if (parent && totchild == 1) {
+ copy_v3_v3(parent->tail, bone->head);
+
+ // not setting BONE_CONNECTED because this would lock child bone location with respect to parent
+ // bone->flag |= BONE_CONNECTED;
+
+ // XXX increase this to prevent "very" small bones?
+ const float epsilon = 0.000001f;
+
+ // derive leaf bone length
+ float length = len_v3v3(parent->head, parent->tail);
+ if ((length < leaf_bone_length || totbone == 0) && length > epsilon) {
+ leaf_bone_length = length;
+ }
+
+ // treat zero-sized bone like a leaf bone
+ if (length <= epsilon) {
+ add_leaf_bone(parent_mat, parent);
+ }
+
+ /*
+#if 0
+ // and which row in mat is bone direction
+ float vec[3];
+ sub_v3_v3v3(vec, parent->tail, parent->head);
+#ifdef COLLADA_DEBUG
+ print_v3("tail - head", vec);
+ print_m4("matrix", parent_mat);
+#endif
+ for (int i = 0; i < 3; i++) {
+#ifdef COLLADA_DEBUG
+ char *axis_names[] = {"X", "Y", "Z"};
+ printf("%s-axis length is %f\n", axis_names[i], len_v3(parent_mat[i]));
+#endif
+ float angle = angle_v2v2(vec, parent_mat[i]);
+ if (angle < min_angle) {
+#ifdef COLLADA_DEBUG
+ print_v3("picking", parent_mat[i]);
+ printf("^ %s axis of %s's matrix\n", axis_names[i], get_dae_name(node));
+#endif
+ bone_direction_row = i;
+ min_angle = angle;
+ }
+ }
+#endif
+ */
+ }
+
+ COLLADAFW::NodePointerArray& children = node->getChildNodes();
+ for (unsigned int i = 0; i < children.getCount(); i++) {
+ create_bone(skin, children[i], bone, children.getCount(), mat, arm);
+ }
+
+ // in second case it's not a leaf bone, but we handle it the same way
+ if (!children.getCount() || children.getCount() > 1) {
+ add_leaf_bone(mat, bone);
+ }
+}
+
+void ArmatureImporter::add_leaf_bone(float mat[][4], EditBone *bone)
+{
+ LeafBone leaf;
+
+ leaf.bone = bone;
+ copy_m4_m4(leaf.mat, mat);
+ BLI_strncpy(leaf.name, bone->name, sizeof(leaf.name));
+
+ leaf_bones.push_back(leaf);
+}
+
+void ArmatureImporter::fix_leaf_bones()
+{
+ // just setting tail for leaf bones here
+
+ std::vector<LeafBone>::iterator it;
+ for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) {
+ LeafBone& leaf = *it;
+
+ // pointing up
+ float vec[3] = {0.0f, 0.0f, 1.0f};
+
+ mul_v3_fl(vec, leaf_bone_length);
+
+ copy_v3_v3(leaf.bone->tail, leaf.bone->head);
+ add_v3_v3v3(leaf.bone->tail, leaf.bone->head, vec);
+ }
+}
+
+void ArmatureImporter::set_leaf_bone_shapes(Object *ob_arm)
+{
+ bPose *pose = ob_arm->pose;
+
+ std::vector<LeafBone>::iterator it;
+ for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) {
+ LeafBone& leaf = *it;
+
+ bPoseChannel *pchan = get_pose_channel(pose, leaf.name);
+ if (pchan) {
+ pchan->custom = get_empty_for_leaves();
+ }
+ else {
+ fprintf(stderr, "Cannot find a pose channel for leaf bone %s\n", leaf.name);
+ }
+ }
+}
+
+#if 0
+void ArmatureImporter::set_euler_rotmode()
+{
+ // just set rotmode = ROT_MODE_EUL on pose channel for each joint
+
+ std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>::iterator it;
+
+ for (it = joint_by_uid.begin(); it != joint_by_uid.end(); it++) {
+
+ COLLADAFW::Node *joint = it->second;
+
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator sit;
+
+ for (sit = skin_by_data_uid.begin(); sit != skin_by_data_uid.end(); sit++) {
+ SkinInfo& skin = sit->second;
+
+ if (skin.uses_joint_or_descendant(joint)) {
+ bPoseChannel *pchan = skin.get_pose_channel_from_node(joint);
+
+ if (pchan) {
+ pchan->rotmode = ROT_MODE_EUL;
+ }
+ else {
+ fprintf(stderr, "Cannot find pose channel for %s.\n", get_joint_name(joint));
+ }
+
+ break;
+ }
+ }
+ }
+}
+#endif
+
+Object *ArmatureImporter::get_empty_for_leaves()
+{
+ if (empty) return empty;
+
+ empty = add_object(scene, OB_EMPTY);
+ empty->empty_drawtype = OB_EMPTY_SPHERE;
+
+ return empty;
+}
+
+#if 0
+Object *ArmatureImporter::find_armature(COLLADAFW::Node *node)
+{
+ JointData* jd = get_joint_data(node);
+ if (jd) return jd->ob_arm;
+
+ COLLADAFW::NodePointerArray& children = node->getChildNodes();
+ for (int i = 0; i < children.getCount(); i++) {
+ Object *ob_arm = find_armature(children[i]);
+ if (ob_arm) return ob_arm;
+ }
+
+ return NULL;
+}
+
+ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm)
+{
+ // try finding it
+ std::vector<ArmatureJoints>::iterator it;
+ for (it = armature_joints.begin(); it != armature_joints.end(); it++) {
+ if ((*it).ob_arm == ob_arm) return *it;
+ }
+
+ // not found, create one
+ ArmatureJoints aj;
+ aj.ob_arm = ob_arm;
+ armature_joints.push_back(aj);
+
+ return armature_joints.back();
+}
+#endif
+
+void ArmatureImporter::create_armature_bones(SkinInfo& skin)
+{
+ // just do like so:
+ // - get armature
+ // - enter editmode
+ // - add edit bones and head/tail properties using matrices and parent-child info
+ // - exit edit mode
+ // - set a sphere shape to leaf bones
+
+ Object *ob_arm = NULL;
+
+ /*
+ * find if there's another skin sharing at least one bone with this skin
+ * if so, use that skin's armature
+ */
+
+ /*
+ Pseudocode:
+
+ find_node_in_tree(node, root_joint)
+
+ skin::find_root_joints(root_joints):
+ std::vector root_joints;
+ for each root in root_joints:
+ for each joint in joints:
+ if find_node_in_tree(joint, root):
+ if (std::find(root_joints.begin(), root_joints.end(), root) == root_joints.end())
+ root_joints.push_back(root);
+
+ for (each skin B with armature) {
+ find all root joints for skin B
+
+ for each joint X in skin A:
+ for each root joint R in skin B:
+ if (find_node_in_tree(X, R)) {
+ shared = 1;
+ goto endloop;
+ }
+ }
+
+ endloop:
+ */
+
+ SkinInfo *a = &skin;
+ Object *shared = NULL;
+ std::vector<COLLADAFW::Node*> skin_root_joints;
+
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+ for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+ SkinInfo *b = &it->second;
+ if (b == a || b->get_armature() == NULL)
+ continue;
+
+ skin_root_joints.clear();
+
+ b->find_root_joints(root_joints, joint_by_uid, skin_root_joints);
+
+ std::vector<COLLADAFW::Node*>::iterator ri;
+ for (ri = skin_root_joints.begin(); ri != skin_root_joints.end(); ri++) {
+ if (a->uses_joint_or_descendant(*ri)) {
+ shared = b->get_armature();
+ break;
+ }
+ }
+
+ if (shared != NULL)
+ break;
+ }
+
+ if (shared)
+ ob_arm = skin.set_armature(shared);
+ else
+ ob_arm = skin.create_armature(scene);
+
+ // enter armature edit mode
+ ED_armature_to_edit(ob_arm);
+
+ leaf_bones.clear();
+ totbone = 0;
+ // bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row
+ leaf_bone_length = 0.1f;
+ // min_angle = 360.0f; // minimum angle between bone head-tail and a row of bone matrix
+
+ // create bones
+ /*
+ TODO:
+ check if bones have already been created for a given joint
+ */
+
+ std::vector<COLLADAFW::Node*>::iterator ri;
+ for (ri = root_joints.begin(); ri != root_joints.end(); ri++) {
+ // for shared armature check if bone tree is already created
+ if (shared && std::find(skin_root_joints.begin(), skin_root_joints.end(), *ri) != skin_root_joints.end())
+ continue;
+
+ // since root_joints may contain joints for multiple controllers, we need to filter
+ if (skin.uses_joint_or_descendant(*ri)) {
+ create_bone(skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature*)ob_arm->data);
+
+ if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent())
+ skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]);
+ }
+ }
+
+ fix_leaf_bones();
+
+ // exit armature edit mode
+ ED_armature_from_edit(ob_arm);
+ ED_armature_edit_free(ob_arm);
+ DAG_id_flush_update(&ob_arm->id, OB_RECALC_OB|OB_RECALC_DATA);
+
+ set_leaf_bone_shapes(ob_arm);
+
+ // set_euler_rotmode();
+}
+
+
+// root - if this joint is the top joint in hierarchy, if a joint
+// is a child of a node (not joint), root should be true since
+// this is where we build armature bones from
+void ArmatureImporter::add_joint(COLLADAFW::Node *node, bool root, Object *parent)
+{
+ joint_by_uid[node->getUniqueId()] = node;
+ if (root) {
+ root_joints.push_back(node);
+
+ if (parent)
+ joint_parent_map[node->getUniqueId()] = parent;
+ }
+}
+
+#if 0
+void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
+{
+ // root_joints.push_back(node);
+ Object *ob_arm = find_armature(node);
+ if (ob_arm) {
+ get_armature_joints(ob_arm).root_joints.push_back(node);
+ }
+#ifdef COLLADA_DEBUG
+ else {
+ fprintf(stderr, "%s cannot be added to armature.\n", get_joint_name(node));
+ }
+#endif
+}
+#endif
+
+// here we add bones to armatures, having armatures previously created in write_controller
+void ArmatureImporter::make_armatures(bContext *C)
+{
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+ for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+
+ SkinInfo& skin = it->second;
+
+ create_armature_bones(skin);
+
+ // link armature with a mesh object
+ Object *ob = mesh_importer->get_object_by_geom_uid(*get_geometry_uid(skin.get_controller_uid()));
+ if (ob)
+ skin.link_armature(C, ob, joint_by_uid, this);
+ else
+ fprintf(stderr, "Cannot find object to link armature with.\n");
+
+ // set armature parent if any
+ Object *par = skin.get_parent();
+ if (par)
+ bc_set_parent(skin.get_armature(), par, C, false);
+
+ // free memory stolen from SkinControllerData
+ skin.free();
+ }
+}
+
+#if 0
+// link with meshes, create vertex groups, assign weights
+void ArmatureImporter::link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id)
+{
+ Object *ob = mesh_importer->get_object_by_geom_uid(geom_id);
+
+ if (!ob) {
+ fprintf(stderr, "Cannot find object by geometry UID.\n");
+ return;
+ }
+
+ if (skin_by_data_uid.find(controller_data_id) == skin_by_data_uid.end()) {
+ fprintf(stderr, "Cannot find skin info by controller data UID.\n");
+ return;
+ }
+
+ SkinInfo& skin = skin_by_data_uid[conroller_data_id];
+
+ // create vertex groups
+}
+#endif
+
+bool ArmatureImporter::write_skin_controller_data(const COLLADAFW::SkinControllerData* data)
+{
+ // at this stage we get vertex influence info that should go into me->verts and ob->defbase
+ // there's no info to which object this should be long so we associate it with skin controller data UID
+
+ // don't forget to call defgroup_unique_name before we copy
+
+ // controller data uid -> [armature] -> joint data,
+ // [mesh object]
+ //
+
+ SkinInfo skin(unit_converter);
+ skin.borrow_skin_controller_data(data);
+
+ // store join inv bind matrix to use it later in armature construction
+ const COLLADAFW::Matrix4Array& inv_bind_mats = data->getInverseBindMatrices();
+ for (unsigned int i = 0; i < data->getJointsCount(); i++) {
+ skin.add_joint(inv_bind_mats[i]);
+ }
+
+ skin_by_data_uid[data->getUniqueId()] = skin;
+
+ return true;
+}
+
+bool ArmatureImporter::write_controller(const COLLADAFW::Controller* controller)
+{
+ // - create and store armature object
+
+ const COLLADAFW::UniqueId& skin_id = controller->getUniqueId();
+
+ if (controller->getControllerType() == COLLADAFW::Controller::CONTROLLER_TYPE_SKIN) {
+ COLLADAFW::SkinController *co = (COLLADAFW::SkinController*)controller;
+ // to be able to find geom id by controller id
+ geom_uid_by_controller_uid[skin_id] = co->getSource();
+
+ const COLLADAFW::UniqueId& data_uid = co->getSkinControllerData();
+ if (skin_by_data_uid.find(data_uid) == skin_by_data_uid.end()) {
+ fprintf(stderr, "Cannot find skin by controller data UID.\n");
+ return true;
+ }
+
+ skin_by_data_uid[data_uid].set_controller(co);
+ }
+ // morph controller
+ else {
+ // shape keys? :)
+ fprintf(stderr, "Morph controller is not supported yet.\n");
+ }
+
+ return true;
+}
+
+COLLADAFW::UniqueId *ArmatureImporter::get_geometry_uid(const COLLADAFW::UniqueId& controller_uid)
+{
+ if (geom_uid_by_controller_uid.find(controller_uid) == geom_uid_by_controller_uid.end())
+ return NULL;
+
+ return &geom_uid_by_controller_uid[controller_uid];
+}
+
+Object *ArmatureImporter::get_armature_for_joint(COLLADAFW::Node *node)
+{
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+ for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+ SkinInfo& skin = it->second;
+
+ if (skin.uses_joint_or_descendant(node))
+ return skin.get_armature();
+ }
+
+ return NULL;
+}
+
+void ArmatureImporter::get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count)
+{
+ BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bc_get_joint_name(node));
+}
+
+// gives a world-space mat
+bool ArmatureImporter::get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint)
+{
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+ bool found = false;
+ for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
+ SkinInfo& skin = it->second;
+ if ((found = skin.get_joint_inv_bind_matrix(m, joint))) {
+ invert_m4(m);
+ break;
+ }
+ }
+
+ return found;
+} \ No newline at end of file
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
new file mode 100644
index 00000000000..64d4669b33c
--- /dev/null
+++ b/source/blender/collada/ArmatureImporter.h
@@ -0,0 +1,160 @@
+/**
+ * $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 *****
+ */
+
+#ifndef __BC_ARMATUREIMPORTER_H__
+#define __BC_ARMATUREIMPORTER_H__
+
+#include "COLLADAFWNode.h"
+#include "COLLADAFWUniqueId.h"
+
+extern "C" {
+#include "BKE_context.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "ED_armature.h"
+}
+
+#include "AnimationImporter.h"
+#include "MeshImporter.h"
+#include "SkinInfo.h"
+#include "TransformReader.h"
+
+#include <map>
+#include <vector>
+
+#include "collada_internal.h"
+#include "collada_utils.h"
+
+class ArmatureImporter : private TransformReader
+{
+private:
+ Scene *scene;
+ UnitConverter *unit_converter;
+
+ // std::map<int, JointData> joint_index_to_joint_info_map;
+ // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
+
+ struct LeafBone {
+ // COLLADAFW::Node *node;
+ EditBone *bone;
+ char name[32];
+ float mat[4][4]; // bone matrix, derived from inv_bind_mat
+ };
+ std::vector<LeafBone> leaf_bones;
+ // int bone_direction_row; // XXX not used
+ float leaf_bone_length;
+ int totbone;
+ // XXX not used
+ // float min_angle; // minimum angle between bone head-tail and a row of bone matrix
+
+#if 0
+ struct ArmatureJoints {
+ Object *ob_arm;
+ std::vector<COLLADAFW::Node*> root_joints;
+ };
+ std::vector<ArmatureJoints> armature_joints;
+#endif
+
+ Object *empty; // empty for leaf bones
+
+ std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> geom_uid_by_controller_uid;
+ std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // contains all joints
+ std::vector<COLLADAFW::Node*> root_joints;
+ std::map<COLLADAFW::UniqueId, Object*> joint_parent_map;
+
+ MeshImporterBase *mesh_importer;
+ AnimationImporterBase *anim_importer;
+
+ // 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.
+
+ std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = skin controller data UID
+#if 0
+ JointData *get_joint_data(COLLADAFW::Node *node);
+#endif
+
+ void create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
+ float parent_mat[][4], bArmature *arm);
+
+ void add_leaf_bone(float mat[][4], EditBone *bone);
+
+ void fix_leaf_bones();
+
+ void set_leaf_bone_shapes(Object *ob_arm);
+
+#if 0
+ void set_euler_rotmode();
+#endif
+
+ Object *get_empty_for_leaves();
+
+#if 0
+ Object *find_armature(COLLADAFW::Node *node);
+
+ ArmatureJoints& get_armature_joints(Object *ob_arm);
+#endif
+
+ void create_armature_bones(SkinInfo& skin);
+
+public:
+
+ ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce);
+ ~ArmatureImporter();
+
+ // root - if this joint is the top joint in hierarchy, if a joint
+ // is a child of a node (not joint), root should be true since
+ // this is where we build armature bones from
+ void add_joint(COLLADAFW::Node *node, bool root, Object *parent);
+
+#if 0
+ void add_root_joint(COLLADAFW::Node *node);
+#endif
+
+ // here we add bones to armatures, having armatures previously created in write_controller
+ void make_armatures(bContext *C);
+
+#if 0
+ // link with meshes, create vertex groups, assign weights
+ void link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id);
+#endif
+
+ bool write_skin_controller_data(const COLLADAFW::SkinControllerData* data);
+
+ bool write_controller(const COLLADAFW::Controller* controller);
+
+ COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId& controller_uid);
+
+ Object *get_armature_for_joint(COLLADAFW::Node *node);
+
+ void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count);
+
+ // gives a world-space mat
+ bool get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint);
+};
+
+#endif \ No newline at end of file
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index d10fa4ca94c..c13e089fa4a 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -91,7 +91,6 @@ extern char build_rev[];
#include "COLLADASWSurfaceInitOption.h"
#include "COLLADASWSampler.h"
#include "COLLADASWScene.h"
-//#include "COLLADASWSurface.h"
#include "COLLADASWTechnique.h"
#include "COLLADASWTexture.h"
#include "COLLADASWLibraryMaterials.h"
@@ -112,31 +111,6 @@ extern char build_rev[];
#include <vector>
#include <algorithm> // std::find
-// arithb.c now has QuatToAxisAngle too
-#if 0
-// This function assumes that quat is normalized.
-// The following document was used as reference:
-// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
-void quat_to_axis_angle( float *axis, float *angle,float *q)
-{
- // quat to axis angle
- *angle = 2 * acos(q[0]);
- float divisor = sqrt(1 - q[0] * q[0]);
-
- // test to avoid divide by zero, divisor is always positive
- if (divisor < 0.001f ) {
- axis[0] = 1.0f;
- axis[1] = 0.0f;
- axis[2] = 0.0f;
- }
- else {
- axis[0] = q[1] / divisor;
- axis[1] = q[2] / divisor;
- axis[2] = q[3] / divisor;
- }
-}
-#endif
-
char *CustomData_get_layer_name(const struct CustomData *data, int type, int n)
{
int layer_index = CustomData_get_layer_index(data, type);
@@ -2580,8 +2554,8 @@ protected:
find_frames(ob, fra, prefix, "rotation_euler");
else if (rotmode == ROT_MODE_QUAT)
find_frames(ob, fra, prefix, "rotation_quaternion");
- else if (rotmode == ROT_MODE_AXISANGLE)
- ;
+ /*else if (rotmode == ROT_MODE_AXISANGLE)
+ ;*/
}
// enable fcurves driving a specific bone, disable all the rest
diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h
index bb6d400fdf1..4aac393b1ab 100644
--- a/source/blender/collada/DocumentExporter.h
+++ b/source/blender/collada/DocumentExporter.h
@@ -21,6 +21,10 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
+#ifndef __DOCUMENTEXPORTER_H__
+#define __DOCUMENTEXPORTER_H__
+
struct Scene;
class DocumentExporter
@@ -29,3 +33,5 @@ class DocumentExporter
void exportCurrentScene(Scene *sce, const char* filename);
void exportScenes(const char* filename);
};
+
+#endif
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 0b50326ad6c..40e4d389b88 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -25,3210 +25,74 @@
// * name imported objects
// * import object rotation as euler
+#include <string>
+#include <map>
+#include <algorithm> // sort()
+
+#include <math.h>
+#include <float.h>
+
#include "COLLADAFWRoot.h"
#include "COLLADAFWIWriter.h"
#include "COLLADAFWStableHeaders.h"
-#include "COLLADAFWAnimationCurve.h"
-#include "COLLADAFWAnimationList.h"
#include "COLLADAFWCamera.h"
#include "COLLADAFWColorOrTexture.h"
#include "COLLADAFWEffect.h"
-#include "COLLADAFWFloatOrDoubleArray.h"
-#include "COLLADAFWGeometry.h"
#include "COLLADAFWImage.h"
#include "COLLADAFWIndexList.h"
#include "COLLADAFWInstanceGeometry.h"
#include "COLLADAFWLight.h"
#include "COLLADAFWMaterial.h"
-#include "COLLADAFWMesh.h"
#include "COLLADAFWMeshPrimitiveWithFaceVertexCount.h"
-#include "COLLADAFWNode.h"
#include "COLLADAFWPolygons.h"
#include "COLLADAFWSampler.h"
-#include "COLLADAFWSkinController.h"
-#include "COLLADAFWSkinControllerData.h"
-#include "COLLADAFWTransformation.h"
-#include "COLLADAFWTranslate.h"
-#include "COLLADAFWRotate.h"
-#include "COLLADAFWScale.h"
-#include "COLLADAFWMatrix.h"
#include "COLLADAFWTypes.h"
#include "COLLADAFWVisualScene.h"
-#include "COLLADAFWFileInfo.h"
#include "COLLADAFWArrayPrimitiveType.h"
#include "COLLADAFWLibraryNodes.h"
#include "COLLADASaxFWLLoader.h"
-// TODO move "extern C" into header files
-extern "C"
-{
-#include "ED_keyframing.h"
-#include "ED_armature.h"
-#include "ED_mesh.h" // ED_vgroup_vert_add, ...
-#include "ED_anim_api.h"
-#include "ED_object.h"
-
-#include "WM_types.h"
-#include "WM_api.h"
-
#include "BKE_main.h"
-#include "BKE_customdata.h"
#include "BKE_library.h"
#include "BKE_texture.h"
#include "BKE_fcurve.h"
#include "BKE_depsgraph.h"
#include "BLI_path_util.h"
-#include "BKE_displist.h"
-#include "BLI_math.h"
#include "BKE_scene.h"
-}
-#include "BKE_armature.h"
-#include "BKE_mesh.h"
#include "BKE_global.h"
-#include "BKE_context.h"
#include "BKE_object.h"
-#include "BKE_image.h"
#include "BKE_material.h"
#include "BKE_utildefines.h"
-#include "BKE_action.h"
+#include "BKE_image.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-#include "DNA_lamp_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_anim_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_texture_types.h"
#include "DNA_camera_types.h"
-#include "DNA_object_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_material_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_modifier_types.h"
+#include "DNA_lamp_types.h"
#include "MEM_guardedalloc.h"
#include "DocumentImporter.h"
#include "collada_internal.h"
-#include <string>
-#include <map>
-#include <algorithm> // sort()
-
-#include <math.h>
-#include <float.h>
-
-// #define COLLADA_DEBUG
-
-// creates empties for each imported bone on layer 2, for debugging
-// #define ARMATURE_TEST
-
-char *CustomData_get_layer_name(const struct CustomData *data, int type, int n);
-
-static const char *primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
-{
- using namespace COLLADAFW;
-
- switch (type) {
- case MeshPrimitive::LINES:
- return "LINES";
- case MeshPrimitive::LINE_STRIPS:
- return "LINESTRIPS";
- case MeshPrimitive::POLYGONS:
- return "POLYGONS";
- case MeshPrimitive::POLYLIST:
- return "POLYLIST";
- case MeshPrimitive::TRIANGLES:
- return "TRIANGLES";
- case MeshPrimitive::TRIANGLE_FANS:
- return "TRIANGLE_FANS";
- case MeshPrimitive::TRIANGLE_STRIPS:
- return "TRIANGLE_FANS";
- case MeshPrimitive::POINTS:
- return "POINTS";
- case MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
- return "UNDEFINED_PRIMITIVE_TYPE";
- }
- return "UNKNOWN";
-}
-
-static const char *geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
-{
- switch (type) {
- case COLLADAFW::Geometry::GEO_TYPE_MESH:
- return "MESH";
- case COLLADAFW::Geometry::GEO_TYPE_SPLINE:
- return "SPLINE";
- case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
- return "CONVEX_MESH";
- case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
- default:
- return "UNKNOWN";
- }
-}
-
-// works for COLLADAFW::Node, COLLADAFW::Geometry
-template<class T>
-static const char *get_dae_name(T *node)
-{
- const std::string& name = node->getName();
- return name.size() ? name.c_str() : node->getOriginalId().c_str();
-}
-
-// use this for retrieving bone names, since these must be unique
-template<class T>
-static const char *get_joint_name(T *node)
-{
- const std::string& id = node->getOriginalId();
- return id.size() ? id.c_str() : node->getName().c_str();
-}
-
-static float get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
-{
- if (index >= array.getValuesCount())
- return 0.0f;
-
- if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
- return array.getFloatValues()->getData()[index];
- else
- return array.getDoubleValues()->getData()[index];
-}
-
-// copied from /editors/object/object_relations.c
-static int test_parent_loop(Object *par, Object *ob)
-{
- /* test if 'ob' is a parent somewhere in par's parents */
-
- if(par == NULL) return 0;
- if(ob == par) return 1;
-
- return test_parent_loop(par->parent, ob);
-}
-
-// a shortened version of parent_set_exec()
-// if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting
-static int set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space=true)
-{
- if (!par || test_parent_loop(par, ob))
- return false;
-
- Object workob;
- Main *bmain = CTX_data_main(C);
- Scene *sce = CTX_data_scene(C);
-
- ob->parent = par;
- ob->partype = PAROBJECT;
-
- ob->parsubstr[0] = 0;
-
- if (is_parent_space) {
- // calc par->obmat
- where_is_object(sce, par);
-
- // move child obmat into world space
- float mat[4][4];
- mul_m4_m4m4(mat, ob->obmat, par->obmat);
- copy_m4_m4(ob->obmat, mat);
- }
-
- // apply child obmat (i.e. decompose it into rot/loc/size)
- object_apply_mat4(ob, ob->obmat);
-
- // compute parentinv
- what_does_parent(sce, ob, &workob);
- invert_m4_m4(ob->parentinv, workob.obmat);
-
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA;
- par->recalc |= OB_RECALC_OB;
-
- DAG_scene_sort(bmain, sce);
- DAG_ids_flush_update(bmain, 0);
- WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
-
- return true;
-}
-
-typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex*> > TexIndexTextureArrayMap;
-
-class TransformReader : public TransformBase
-{
-protected:
-
- UnitConverter *unit_converter;
-
- struct Animation {
- Object *ob;
- COLLADAFW::Node *node;
- COLLADAFW::Transformation *tm; // which transform is animated by an AnimationList->id
- };
-
-public:
-
- TransformReader(UnitConverter* conv) : unit_converter(conv) {}
-
- void get_node_mat(float mat[][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map,
- Object *ob)
- {
- float cur[4][4];
- float copy[4][4];
-
- unit_m4(mat);
-
- for (unsigned int i = 0; i < node->getTransformations().getCount(); i++) {
-
- COLLADAFW::Transformation *tm = node->getTransformations()[i];
- COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
-
- switch(type) {
- case COLLADAFW::Transformation::TRANSLATE:
- dae_translate_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::ROTATE:
- dae_rotate_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::SCALE:
- dae_scale_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::MATRIX:
- dae_matrix_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::LOOKAT:
- case COLLADAFW::Transformation::SKEW:
- fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
- break;
- }
-
- copy_m4_m4(copy, mat);
- mul_m4_m4m4(mat, cur, copy);
-
- if (animation_map) {
- // AnimationList that drives this Transformation
- const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList();
-
- // store this so later we can link animation data with ob
- Animation anim = {ob, node, tm};
- (*animation_map)[anim_list_id] = anim;
- }
- }
- }
-
- void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
- {
- COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm;
- COLLADABU::Math::Vector3& axis = ro->getRotationAxis();
- float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f);
- float ax[] = {axis[0], axis[1], axis[2]};
- // float quat[4];
- // axis_angle_to_quat(quat, axis, angle);
- // quat_to_mat4(m, quat);
- axis_angle_to_mat4(m, ax, angle);
- }
-
- void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
- {
- COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm;
- COLLADABU::Math::Vector3& t = tra->getTranslation();
-
- unit_m4(m);
-
- m[3][0] = (float)t[0];
- m[3][1] = (float)t[1];
- m[3][2] = (float)t[2];
- }
-
- void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
- {
- COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale();
- float size[3] = {(float)s[0], (float)s[1], (float)s[2]};
- size_to_mat4(m, size);
- }
-
- void dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
- {
- unit_converter->dae_matrix_to_mat4(m, ((COLLADAFW::Matrix*)tm)->getMatrix());
- }
-
- void dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3])
- {
- dae_vector3_to_v3(((COLLADAFW::Translate*)tm)->getTranslation(), v);
- }
-
- void dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3])
- {
- dae_vector3_to_v3(((COLLADAFW::Scale*)tm)->getScale(), v);
- }
-
- void dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3])
- {
- v[0] = v3.x;
- v[1] = v3.y;
- v[2] = v3.z;
- }
-};
-
-// only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid
-class MeshImporterBase
-{
-public:
- virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0;
-};
-
-// ditto as above
-class AnimationImporterBase
-{
-public:
- // virtual void change_eul_to_quat(Object *ob, bAction *act) = 0;
-};
-
-class ArmatureImporter : private TransformReader
-{
-private:
- Scene *scene;
- UnitConverter *unit_converter;
-
- // std::map<int, JointData> joint_index_to_joint_info_map;
- // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
-
- struct LeafBone {
- // COLLADAFW::Node *node;
- EditBone *bone;
- char name[32];
- float mat[4][4]; // bone matrix, derived from inv_bind_mat
- };
- std::vector<LeafBone> leaf_bones;
- // int bone_direction_row; // XXX not used
- float leaf_bone_length;
- int totbone;
- // XXX not used
- // float min_angle; // minimum angle between bone head-tail and a row of bone matrix
-
-#if 0
- struct ArmatureJoints {
- Object *ob_arm;
- std::vector<COLLADAFW::Node*> root_joints;
- };
- std::vector<ArmatureJoints> armature_joints;
-#endif
-
- Object *empty; // empty for leaf bones
-
- std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> geom_uid_by_controller_uid;
- std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // contains all joints
- std::vector<COLLADAFW::Node*> root_joints;
- std::map<COLLADAFW::UniqueId, Object*> joint_parent_map;
-
- MeshImporterBase *mesh_importer;
- AnimationImporterBase *anim_importer;
-
- // 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.
- class SkinInfo
- {
- private:
- // to build armature bones from inverse bind matrices
- struct JointData {
- float inv_bind_mat[4][4]; // joint inverse bind matrix
- COLLADAFW::UniqueId joint_uid; // joint node UID
- // Object *ob_arm; // armature object
- };
-
- float bind_shape_matrix[4][4];
-
- // data from COLLADAFW::SkinControllerData, each array should be freed
- COLLADAFW::UIntValuesArray joints_per_vertex;
- COLLADAFW::UIntValuesArray weight_indices;
- COLLADAFW::IntValuesArray joint_indices;
- // COLLADAFW::FloatOrDoubleArray weights;
- std::vector<float> weights;
-
- std::vector<JointData> joint_data; // index to this vector is joint index
-
- UnitConverter *unit_converter;
-
- Object *ob_arm;
- COLLADAFW::UniqueId controller_uid;
- Object *parent;
-
- public:
-
- 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(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 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 transfer_int_array_data_const(const COLLADAFW::IntValuesArray& src, COLLADAFW::IntValuesArray& dest)
- {
- dest.setData((int*)src.getData(), src.getCount());
- dest.yieldOwnerShip();
- }
-
- void transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest)
- {
- dest.setData((unsigned int*)src.getData(), src.getCount());
- dest.yieldOwnerShip();
- }
-
- void 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(get_float_value(weight, i));
-
- unit_converter->dae_matrix_to_mat4(bind_shape_matrix, skin->getBindShapeMatrix());
- }
-
- void 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 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 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 *create_armature(Scene *scene)
- {
- ob_arm = add_object(scene, OB_ARMATURE);
- return ob_arm;
- }
-
- Object* set_armature(Object *ob_arm)
- {
- if (this->ob_arm)
- return this->ob_arm;
-
- this->ob_arm = ob_arm;
- return ob_arm;
- }
-
- bool 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 *get_armature()
- {
- return ob_arm;
- }
-
- const COLLADAFW::UniqueId& 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 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 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
- ::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 = 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 *get_pose_channel_from_node(COLLADAFW::Node *node)
- {
- return get_pose_channel(ob_arm->pose, get_joint_name(node));
- }
-
- void set_parent(Object *_parent)
- {
- parent = _parent;
- }
-
- Object* get_parent()
- {
- return parent;
- }
-
- void 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 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;
- }
-
- };
-
- std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = skin controller data UID
-#if 0
- JointData *get_joint_data(COLLADAFW::Node *node)
- {
- const COLLADAFW::UniqueId& joint_id = node->getUniqueId();
-
- if (joint_id_to_joint_index_map.find(joint_id) == joint_id_to_joint_index_map.end()) {
- fprintf(stderr, "Cannot find a joint index by joint id for %s.\n",
- node->getOriginalId().c_str());
- return NULL;
- }
-
- int joint_index = joint_id_to_joint_index_map[joint_id];
-
- return &joint_index_to_joint_info_map[joint_index];
- }
-#endif
-
- void create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
- float parent_mat[][4], bArmature *arm)
- {
- float joint_inv_bind_mat[4][4];
-
- // JointData* jd = get_joint_data(node);
-
- float mat[4][4];
-
- if (skin.get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
- // get original world-space matrix
- invert_m4_m4(mat, joint_inv_bind_mat);
- }
- // create a bone even if there's no joint data for it (i.e. it has no influence)
- else {
- float obmat[4][4];
-
- // object-space
- get_node_mat(obmat, node, NULL, NULL);
-
- // get world-space
- if (parent)
- mul_m4_m4m4(mat, obmat, parent_mat);
- else
- copy_m4_m4(mat, obmat);
- }
-
- // TODO rename from Node "name" attrs later
- EditBone *bone = ED_armature_edit_bone_add(arm, (char*)get_joint_name(node));
- totbone++;
-
- if (parent) bone->parent = parent;
-
- // set head
- copy_v3_v3(bone->head, mat[3]);
-
- // set tail, don't set it to head because 0-length bones are not allowed
- float vec[3] = {0.0f, 0.5f, 0.0f};
- add_v3_v3v3(bone->tail, bone->head, vec);
-
- // set parent tail
- if (parent && totchild == 1) {
- copy_v3_v3(parent->tail, bone->head);
-
- // not setting BONE_CONNECTED because this would lock child bone location with respect to parent
- // bone->flag |= BONE_CONNECTED;
-
- // XXX increase this to prevent "very" small bones?
- const float epsilon = 0.000001f;
-
- // derive leaf bone length
- float length = len_v3v3(parent->head, parent->tail);
- if ((length < leaf_bone_length || totbone == 0) && length > epsilon) {
- leaf_bone_length = length;
- }
-
- // treat zero-sized bone like a leaf bone
- if (length <= epsilon) {
- add_leaf_bone(parent_mat, parent);
- }
-
- /*
-#if 0
- // and which row in mat is bone direction
- float vec[3];
- sub_v3_v3v3(vec, parent->tail, parent->head);
-#ifdef COLLADA_DEBUG
- print_v3("tail - head", vec);
- print_m4("matrix", parent_mat);
-#endif
- for (int i = 0; i < 3; i++) {
-#ifdef COLLADA_DEBUG
- char *axis_names[] = {"X", "Y", "Z"};
- printf("%s-axis length is %f\n", axis_names[i], len_v3(parent_mat[i]));
-#endif
- float angle = angle_v2v2(vec, parent_mat[i]);
- if (angle < min_angle) {
-#ifdef COLLADA_DEBUG
- print_v3("picking", parent_mat[i]);
- printf("^ %s axis of %s's matrix\n", axis_names[i], get_dae_name(node));
-#endif
- bone_direction_row = i;
- min_angle = angle;
- }
- }
-#endif
- */
- }
-
- COLLADAFW::NodePointerArray& children = node->getChildNodes();
- for (unsigned int i = 0; i < children.getCount(); i++) {
- create_bone(skin, children[i], bone, children.getCount(), mat, arm);
- }
-
- // in second case it's not a leaf bone, but we handle it the same way
- if (!children.getCount() || children.getCount() > 1) {
- add_leaf_bone(mat, bone);
- }
- }
-
- void add_leaf_bone(float mat[][4], EditBone *bone)
- {
- LeafBone leaf;
-
- leaf.bone = bone;
- copy_m4_m4(leaf.mat, mat);
- BLI_strncpy(leaf.name, bone->name, sizeof(leaf.name));
-
- leaf_bones.push_back(leaf);
- }
-
- void fix_leaf_bones()
- {
- // just setting tail for leaf bones here
-
- std::vector<LeafBone>::iterator it;
- for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) {
- LeafBone& leaf = *it;
-
- // pointing up
- float vec[3] = {0.0f, 0.0f, 1.0f};
-
- mul_v3_fl(vec, leaf_bone_length);
-
- copy_v3_v3(leaf.bone->tail, leaf.bone->head);
- add_v3_v3v3(leaf.bone->tail, leaf.bone->head, vec);
- }
- }
-
- void set_leaf_bone_shapes(Object *ob_arm)
- {
- bPose *pose = ob_arm->pose;
-
- std::vector<LeafBone>::iterator it;
- for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) {
- LeafBone& leaf = *it;
-
- bPoseChannel *pchan = get_pose_channel(pose, leaf.name);
- if (pchan) {
- pchan->custom = get_empty_for_leaves();
- }
- else {
- fprintf(stderr, "Cannot find a pose channel for leaf bone %s\n", leaf.name);
- }
- }
- }
-
-#if 0
- void set_euler_rotmode()
- {
- // just set rotmode = ROT_MODE_EUL on pose channel for each joint
-
- std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>::iterator it;
-
- for (it = joint_by_uid.begin(); it != joint_by_uid.end(); it++) {
-
- COLLADAFW::Node *joint = it->second;
-
- std::map<COLLADAFW::UniqueId, SkinInfo>::iterator sit;
-
- for (sit = skin_by_data_uid.begin(); sit != skin_by_data_uid.end(); sit++) {
- SkinInfo& skin = sit->second;
-
- if (skin.uses_joint_or_descendant(joint)) {
- bPoseChannel *pchan = skin.get_pose_channel_from_node(joint);
-
- if (pchan) {
- pchan->rotmode = ROT_MODE_EUL;
- }
- else {
- fprintf(stderr, "Cannot find pose channel for %s.\n", get_joint_name(joint));
- }
-
- break;
- }
- }
- }
- }
-#endif
-
- Object *get_empty_for_leaves()
- {
- if (empty) return empty;
-
- empty = add_object(scene, OB_EMPTY);
- empty->empty_drawtype = OB_EMPTY_SPHERE;
-
- return empty;
- }
-
-#if 0
- Object *find_armature(COLLADAFW::Node *node)
- {
- JointData* jd = get_joint_data(node);
- if (jd) return jd->ob_arm;
-
- COLLADAFW::NodePointerArray& children = node->getChildNodes();
- for (int i = 0; i < children.getCount(); i++) {
- Object *ob_arm = find_armature(children[i]);
- if (ob_arm) return ob_arm;
- }
-
- return NULL;
- }
-
- ArmatureJoints& get_armature_joints(Object *ob_arm)
- {
- // try finding it
- std::vector<ArmatureJoints>::iterator it;
- for (it = armature_joints.begin(); it != armature_joints.end(); it++) {
- if ((*it).ob_arm == ob_arm) return *it;
- }
-
- // not found, create one
- ArmatureJoints aj;
- aj.ob_arm = ob_arm;
- armature_joints.push_back(aj);
-
- return armature_joints.back();
- }
-#endif
-
- void create_armature_bones(SkinInfo& skin)
- {
- // just do like so:
- // - get armature
- // - enter editmode
- // - add edit bones and head/tail properties using matrices and parent-child info
- // - exit edit mode
- // - set a sphere shape to leaf bones
-
- Object *ob_arm = NULL;
-
- /*
- * find if there's another skin sharing at least one bone with this skin
- * if so, use that skin's armature
- */
-
- /*
- Pseudocode:
-
- find_node_in_tree(node, root_joint)
-
- skin::find_root_joints(root_joints):
- std::vector root_joints;
- for each root in root_joints:
- for each joint in joints:
- if find_node_in_tree(joint, root):
- if (std::find(root_joints.begin(), root_joints.end(), root) == root_joints.end())
- root_joints.push_back(root);
-
- for (each skin B with armature) {
- find all root joints for skin B
-
- for each joint X in skin A:
- for each root joint R in skin B:
- if (find_node_in_tree(X, R)) {
- shared = 1;
- goto endloop;
- }
- }
-
- endloop:
- */
-
- SkinInfo *a = &skin;
- Object *shared = NULL;
- std::vector<COLLADAFW::Node*> skin_root_joints;
-
- std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
- for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
- SkinInfo *b = &it->second;
- if (b == a || b->get_armature() == NULL)
- continue;
-
- skin_root_joints.clear();
-
- b->find_root_joints(root_joints, joint_by_uid, skin_root_joints);
-
- std::vector<COLLADAFW::Node*>::iterator ri;
- for (ri = skin_root_joints.begin(); ri != skin_root_joints.end(); ri++) {
- if (a->uses_joint_or_descendant(*ri)) {
- shared = b->get_armature();
- break;
- }
- }
-
- if (shared != NULL)
- break;
- }
-
- if (shared)
- ob_arm = skin.set_armature(shared);
- else
- ob_arm = skin.create_armature(scene);
-
- // enter armature edit mode
- ED_armature_to_edit(ob_arm);
-
- leaf_bones.clear();
- totbone = 0;
- // bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row
- leaf_bone_length = 0.1f;
- // min_angle = 360.0f; // minimum angle between bone head-tail and a row of bone matrix
-
- // create bones
- /*
- TODO:
- check if bones have already been created for a given joint
- */
-
- std::vector<COLLADAFW::Node*>::iterator ri;
- for (ri = root_joints.begin(); ri != root_joints.end(); ri++) {
- // for shared armature check if bone tree is already created
- if (shared && std::find(skin_root_joints.begin(), skin_root_joints.end(), *ri) != skin_root_joints.end())
- continue;
-
- // since root_joints may contain joints for multiple controllers, we need to filter
- if (skin.uses_joint_or_descendant(*ri)) {
- create_bone(skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature*)ob_arm->data);
-
- if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent())
- skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]);
- }
- }
-
- fix_leaf_bones();
-
- // exit armature edit mode
- ED_armature_from_edit(ob_arm);
- ED_armature_edit_free(ob_arm);
- DAG_id_flush_update(&ob_arm->id, OB_RECALC_OB|OB_RECALC_DATA);
-
- set_leaf_bone_shapes(ob_arm);
-
- // set_euler_rotmode();
- }
-
-
-public:
-
- ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce) :
- TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh), anim_importer(anim) {}
-
- ~ArmatureImporter()
- {
- // free skin controller data if we forget to do this earlier
- std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
- for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
- it->second.free();
- }
- }
-
- // root - if this joint is the top joint in hierarchy, if a joint
- // is a child of a node (not joint), root should be true since
- // this is where we build armature bones from
- void add_joint(COLLADAFW::Node *node, bool root, Object *parent)
- {
- joint_by_uid[node->getUniqueId()] = node;
- if (root) {
- root_joints.push_back(node);
-
- if (parent)
- joint_parent_map[node->getUniqueId()] = parent;
- }
- }
-
-#if 0
- void add_root_joint(COLLADAFW::Node *node)
- {
- // root_joints.push_back(node);
- Object *ob_arm = find_armature(node);
- if (ob_arm) {
- get_armature_joints(ob_arm).root_joints.push_back(node);
- }
-#ifdef COLLADA_DEBUG
- else {
- fprintf(stderr, "%s cannot be added to armature.\n", get_joint_name(node));
- }
-#endif
- }
-#endif
-
- // here we add bones to armatures, having armatures previously created in write_controller
- void make_armatures(bContext *C)
- {
- std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
- for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
-
- SkinInfo& skin = it->second;
-
- create_armature_bones(skin);
-
- // link armature with a mesh object
- Object *ob = mesh_importer->get_object_by_geom_uid(*get_geometry_uid(skin.get_controller_uid()));
- if (ob)
- skin.link_armature(C, ob, joint_by_uid, this);
- else
- fprintf(stderr, "Cannot find object to link armature with.\n");
-
- // set armature parent if any
- Object *par = skin.get_parent();
- if (par)
- set_parent(skin.get_armature(), par, C, false);
-
- // free memory stolen from SkinControllerData
- skin.free();
- }
- }
-
-#if 0
- // link with meshes, create vertex groups, assign weights
- void link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id)
- {
- Object *ob = mesh_importer->get_object_by_geom_uid(geom_id);
-
- if (!ob) {
- fprintf(stderr, "Cannot find object by geometry UID.\n");
- return;
- }
-
- if (skin_by_data_uid.find(controller_data_id) == skin_by_data_uid.end()) {
- fprintf(stderr, "Cannot find skin info by controller data UID.\n");
- return;
- }
-
- SkinInfo& skin = skin_by_data_uid[conroller_data_id];
-
- // create vertex groups
- }
-#endif
-
- bool write_skin_controller_data(const COLLADAFW::SkinControllerData* data)
- {
- // at this stage we get vertex influence info that should go into me->verts and ob->defbase
- // there's no info to which object this should be long so we associate it with skin controller data UID
-
- // don't forget to call defgroup_unique_name before we copy
-
- // controller data uid -> [armature] -> joint data,
- // [mesh object]
- //
-
- SkinInfo skin(unit_converter);
- skin.borrow_skin_controller_data(data);
-
- // store join inv bind matrix to use it later in armature construction
- const COLLADAFW::Matrix4Array& inv_bind_mats = data->getInverseBindMatrices();
- for (unsigned int i = 0; i < data->getJointsCount(); i++) {
- skin.add_joint(inv_bind_mats[i]);
- }
-
- skin_by_data_uid[data->getUniqueId()] = skin;
-
- return true;
- }
-
- bool write_controller(const COLLADAFW::Controller* controller)
- {
- // - create and store armature object
-
- const COLLADAFW::UniqueId& skin_id = controller->getUniqueId();
-
- if (controller->getControllerType() == COLLADAFW::Controller::CONTROLLER_TYPE_SKIN) {
- COLLADAFW::SkinController *co = (COLLADAFW::SkinController*)controller;
- // to be able to find geom id by controller id
- geom_uid_by_controller_uid[skin_id] = co->getSource();
-
- const COLLADAFW::UniqueId& data_uid = co->getSkinControllerData();
- if (skin_by_data_uid.find(data_uid) == skin_by_data_uid.end()) {
- fprintf(stderr, "Cannot find skin by controller data UID.\n");
- return true;
- }
-
- skin_by_data_uid[data_uid].set_controller(co);
- }
- // morph controller
- else {
- // shape keys? :)
- fprintf(stderr, "Morph controller is not supported yet.\n");
- }
-
- return true;
- }
-
- COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId& controller_uid)
- {
- if (geom_uid_by_controller_uid.find(controller_uid) == geom_uid_by_controller_uid.end())
- return NULL;
-
- return &geom_uid_by_controller_uid[controller_uid];
- }
-
- Object *get_armature_for_joint(COLLADAFW::Node *node)
- {
- std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
- for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
- SkinInfo& skin = it->second;
-
- if (skin.uses_joint_or_descendant(node))
- return skin.get_armature();
- }
-
- return NULL;
- }
-
- void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count)
- {
- BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", get_joint_name(node));
- }
-
- // gives a world-space mat
- bool get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint)
- {
- std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
- bool found = false;
- for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
- SkinInfo& skin = it->second;
- if ((found = skin.get_joint_inv_bind_matrix(m, joint))) {
- invert_m4(m);
- break;
- }
- }
-
- return found;
- }
-};
-
-class MeshImporter : public MeshImporterBase
-{
-private:
-
- Scene *scene;
- ArmatureImporter *armature_importer;
-
- std::map<COLLADAFW::UniqueId, Mesh*> uid_mesh_map; // geometry unique id-to-mesh map
- std::map<COLLADAFW::UniqueId, Object*> uid_object_map; // geom uid-to-object
- // this structure is used to assign material indices to faces
- // it holds a portion of Mesh faces and corresponds to a DAE primitive list (<triangles>, <polylist>, etc.)
- struct Primitive {
- MFace *mface;
- unsigned int totface;
- };
- typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap;
- std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name!
-
- class UVDataWrapper
- {
- COLLADAFW::MeshVertexData *mVData;
- public:
- UVDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata)
- {}
-
-#ifdef COLLADA_DEBUG
- void print()
- {
- fprintf(stderr, "UVs:\n");
- switch(mVData->getType()) {
- case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
- {
- COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
- if (values->getCount()) {
- for (int i = 0; i < values->getCount(); i += 2) {
- fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i+1]);
- }
- }
- }
- break;
- case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
- {
- COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
- if (values->getCount()) {
- for (int i = 0; i < values->getCount(); i += 2) {
- fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i+1]);
- }
- }
- }
- break;
- }
- fprintf(stderr, "\n");
- }
-#endif
-
- void getUV(int uv_index[2], float *uv)
- {
- switch(mVData->getType()) {
- case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
- {
- COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
- if (values->empty()) return;
- uv[0] = (*values)[uv_index[0]];
- uv[1] = (*values)[uv_index[1]];
-
- }
- break;
- case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
- {
- COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
- if (values->empty()) return;
- uv[0] = (float)(*values)[uv_index[0]];
- uv[1] = (float)(*values)[uv_index[1]];
-
- }
- break;
- case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
- default:
- fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
- }
- }
- };
-
- void set_face_indices(MFace *mface, unsigned int *indices, bool quad)
- {
- mface->v1 = indices[0];
- mface->v2 = indices[1];
- mface->v3 = indices[2];
- if (quad) mface->v4 = indices[3];
- else mface->v4 = 0;
-#ifdef COLLADA_DEBUG
- // fprintf(stderr, "%u, %u, %u \n", indices[0], indices[1], indices[2]);
-#endif
- }
-
- // not used anymore, test_index_face from blenkernel is better
-#if 0
- // change face indices order so that v4 is not 0
- void rotate_face_indices(MFace *mface) {
- mface->v4 = mface->v1;
- mface->v1 = mface->v2;
- mface->v2 = mface->v3;
- mface->v3 = 0;
- }
-#endif
-
- void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, unsigned int *tris_indices)
- {
- int uv_indices[4][2];
-
- // per face vertex indices, this means for quad we have 4 indices, not 8
- COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
-
- // make indices into FloatOrDoubleArray
- for (int i = 0; i < 3; i++) {
- int uv_index = indices[tris_indices[i]];
- uv_indices[i][0] = uv_index * 2;
- uv_indices[i][1] = uv_index * 2 + 1;
- }
-
- uvs.getUV(uv_indices[0], mtface->uv[0]);
- uvs.getUV(uv_indices[1], mtface->uv[1]);
- uvs.getUV(uv_indices[2], mtface->uv[2]);
- }
-
- void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, int index, bool quad)
- {
- int uv_indices[4][2];
-
- // per face vertex indices, this means for quad we have 4 indices, not 8
- COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
-
- // make indices into FloatOrDoubleArray
- for (int i = 0; i < (quad ? 4 : 3); i++) {
- int uv_index = indices[index + i];
- uv_indices[i][0] = uv_index * 2;
- uv_indices[i][1] = uv_index * 2 + 1;
- }
-
- uvs.getUV(uv_indices[0], mtface->uv[0]);
- uvs.getUV(uv_indices[1], mtface->uv[1]);
- uvs.getUV(uv_indices[2], mtface->uv[2]);
-
- if (quad) uvs.getUV(uv_indices[3], mtface->uv[3]);
-
-#ifdef COLLADA_DEBUG
- /*if (quad) {
- fprintf(stderr, "face uv:\n"
- "((%d, %d), (%d, %d), (%d, %d), (%d, %d))\n"
- "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
-
- uv_indices[0][0], uv_indices[0][1],
- uv_indices[1][0], uv_indices[1][1],
- uv_indices[2][0], uv_indices[2][1],
- uv_indices[3][0], uv_indices[3][1],
-
- mtface->uv[0][0], mtface->uv[0][1],
- mtface->uv[1][0], mtface->uv[1][1],
- mtface->uv[2][0], mtface->uv[2][1],
- mtface->uv[3][0], mtface->uv[3][1]);
- }
- else {
- fprintf(stderr, "face uv:\n"
- "((%d, %d), (%d, %d), (%d, %d))\n"
- "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
-
- uv_indices[0][0], uv_indices[0][1],
- uv_indices[1][0], uv_indices[1][1],
- uv_indices[2][0], uv_indices[2][1],
-
- mtface->uv[0][0], mtface->uv[0][1],
- mtface->uv[1][0], mtface->uv[1][1],
- mtface->uv[2][0], mtface->uv[2][1]);
- }*/
-#endif
- }
-
-#ifdef COLLADA_DEBUG
- void print_index_list(COLLADAFW::IndexList& index_list)
- {
- fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str());
- for (int i = 0; i < index_list.getIndicesCount(); i += 2) {
- fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1));
- }
- fprintf(stderr, "\n");
- }
-#endif
-
- bool is_nice_mesh(COLLADAFW::Mesh *mesh)
- {
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
-
- const char *name = get_dae_name(mesh);
-
- for (unsigned i = 0; i < prim_arr.getCount(); i++) {
-
- COLLADAFW::MeshPrimitive *mp = prim_arr[i];
- COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
-
- const char *type_str = primTypeToStr(type);
-
- // OpenCollada passes POLYGONS type for <polylist>
- if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
-
- COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
- COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray();
-
- for(unsigned int j = 0; j < vca.getCount(); j++){
- int count = vca[j];
- if (count < 3) {
- fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n",
- type_str, name);
- return false;
- }
- }
-
- }
- else if(type != COLLADAFW::MeshPrimitive::TRIANGLES) {
- fprintf(stderr, "Primitive type %s is not supported.\n", type_str);
- return false;
- }
- }
-
- if (mesh->getPositions().empty()) {
- fprintf(stderr, "Mesh %s has no vertices.\n", name);
- return false;
- }
-
- return true;
- }
-
- void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
- {
- // vertices
- me->totvert = mesh->getPositions().getFloatValues()->getCount() / 3;
- me->mvert = (MVert*)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
-
- COLLADAFW::MeshVertexData& pos = mesh->getPositions();
- MVert *mvert;
- int i;
-
- for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++)
- get_vector(mvert->co, pos, i);
- }
-
- int triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri)
- {
- ListBase dispbase;
- DispList *dl;
- float *vert;
- int i = 0;
-
- dispbase.first = dispbase.last = NULL;
-
- dl = (DispList*)MEM_callocN(sizeof(DispList), "poly disp");
- dl->nr = totvert;
- dl->type = DL_POLY;
- dl->parts = 1;
- dl->verts = vert = (float*)MEM_callocN(totvert * 3 * sizeof(float), "poly verts");
- dl->index = (int*)MEM_callocN(sizeof(int) * 3 * totvert, "dl index");
-
- BLI_addtail(&dispbase, dl);
-
- for (i = 0; i < totvert; i++) {
- copy_v3_v3(vert, verts[indices[i]].co);
- vert += 3;
- }
-
- filldisplist(&dispbase, &dispbase, 0);
-
- int tottri = 0;
- dl= (DispList*)dispbase.first;
-
- if (dl->type == DL_INDEX3) {
- tottri = dl->parts;
-
- int *index = dl->index;
- for (i= 0; i < tottri; i++) {
- int t[3]= {*index, *(index + 1), *(index + 2)};
-
- std::sort(t, t + 3);
-
- tri.push_back(t[0]);
- tri.push_back(t[1]);
- tri.push_back(t[2]);
-
- index += 3;
- }
- }
-
- freedisplist(&dispbase);
-
- return tottri;
- }
-
- int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me)
- {
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
- unsigned int i;
- int tottri = 0;
-
- for (i = 0; i < prim_arr.getCount(); i++) {
-
- COLLADAFW::MeshPrimitive *mp = prim_arr[i];
- int type = mp->getPrimitiveType();
- size_t prim_totface = mp->getFaceCount();
- unsigned int *indices = mp->getPositionIndices().getData();
-
- if (type == COLLADAFW::MeshPrimitive::POLYLIST ||
- type == COLLADAFW::MeshPrimitive::POLYGONS) {
-
- COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
- COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
-
- for (unsigned int j = 0; j < prim_totface; j++) {
- int vcount = vcounta[j];
-
- if (vcount > 4) {
- std::vector<unsigned int> tri;
-
- // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?!
- tottri += triangulate_poly(indices, vcount, me->mvert, tri);
- }
-
- indices += vcount;
- }
- }
- }
- return tottri;
- }
-
- // TODO: import uv set names
- void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris)
- {
- unsigned int i;
-
- // allocate faces
- me->totface = mesh->getFacesCount() + new_tris;
- me->mface = (MFace*)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
-
- // allocate UV layers
- unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount();
-
- for (i = 0; i < totuvset; i++) {
- if (mesh->getUVCoords().getLength(i) == 0) {
- totuvset = 0;
- break;
- }
- }
-
- for (i = 0; i < totuvset; i++) {
- COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i];
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str());
- //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
- }
-
- // activate the first uv layer
- if (totuvset) me->mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0);
-
- UVDataWrapper uvs(mesh->getUVCoords());
-
-#ifdef COLLADA_DEBUG
- // uvs.print();
-#endif
-
- MFace *mface = me->mface;
-
- MaterialIdPrimitiveArrayMap mat_prim_map;
-
- int face_index = 0;
-
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
-
- bool has_normals = mesh->hasNormals();
- COLLADAFW::MeshVertexData& nor = mesh->getNormals();
-
- for (i = 0; i < prim_arr.getCount(); i++) {
-
- COLLADAFW::MeshPrimitive *mp = prim_arr[i];
-
- // faces
- size_t prim_totface = mp->getFaceCount();
- unsigned int *indices = mp->getPositionIndices().getData();
- unsigned int *nind = mp->getNormalIndices().getData();
- unsigned int j, k;
- int type = mp->getPrimitiveType();
- int index = 0;
-
- // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive
- Primitive prim = {mface, 0};
- COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray();
-
-#ifdef COLLADA_DEBUG
- /*
- fprintf(stderr, "Primitive %d:\n", i);
- for (int j = 0; j < totuvset; j++) {
- print_index_list(*index_list_array[j]);
- }
- */
-#endif
-
- if (type == COLLADAFW::MeshPrimitive::TRIANGLES) {
- for (j = 0; j < prim_totface; j++){
-
- set_face_indices(mface, indices, false);
- indices += 3;
-
-#if 0
- for (k = 0; k < totuvset; k++) {
- if (!index_list_array.empty() && index_list_array[k]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false);
- }
- }
-#else
- for (k = 0; k < index_list_array.getCount(); k++) {
- int uvset_index = index_list_array[k]->getSetIndex();
-
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false);
- }
-#endif
-
- test_index_face(mface, &me->fdata, face_index, 3);
-
- if (has_normals) {
- if (!flat_face(nind, nor, 3))
- mface->flag |= ME_SMOOTH;
-
- nind += 3;
- }
-
- index += 3;
- mface++;
- face_index++;
- prim.totface++;
- }
- }
- else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
- COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
- COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
-
- for (j = 0; j < prim_totface; j++) {
-
- // face
- int vcount = vcounta[j];
- if (vcount == 3 || vcount == 4) {
-
- set_face_indices(mface, indices, vcount == 4);
-
- // set mtface for each uv set
- // it is assumed that all primitives have equal number of UV sets
-
-#if 0
- for (k = 0; k < totuvset; k++) {
- if (!index_list_array.empty() && index_list_array[k]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0);
- }
- }
-#else
- for (k = 0; k < index_list_array.getCount(); k++) {
- int uvset_index = index_list_array[k]->getSetIndex();
-
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, mface->v4 != 0);
- }
-#endif
-
- test_index_face(mface, &me->fdata, face_index, vcount);
-
- if (has_normals) {
- if (!flat_face(nind, nor, vcount))
- mface->flag |= ME_SMOOTH;
-
- nind += vcount;
- }
-
- mface++;
- face_index++;
- prim.totface++;
-
- }
- else {
- std::vector<unsigned int> tri;
-
- triangulate_poly(indices, vcount, me->mvert, tri);
-
- for (k = 0; k < tri.size() / 3; k++) {
- int v = k * 3;
- unsigned int uv_indices[3] = {
- index + tri[v],
- index + tri[v + 1],
- index + tri[v + 2]
- };
- unsigned int tri_indices[3] = {
- indices[tri[v]],
- indices[tri[v + 1]],
- indices[tri[v + 2]]
- };
-
- set_face_indices(mface, tri_indices, false);
-
-#if 0
- for (unsigned int l = 0; l < totuvset; l++) {
- if (!index_list_array.empty() && index_list_array[l]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l);
- set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices);
- }
- }
-#else
- for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
- int uvset_index = index_list_array[l]->getSetIndex();
-
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices);
- }
-#endif
-
-
- test_index_face(mface, &me->fdata, face_index, 3);
-
- if (has_normals) {
- unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]};
-
- if (!flat_face(ntri, nor, 3))
- mface->flag |= ME_SMOOTH;
- }
-
- mface++;
- face_index++;
- prim.totface++;
- }
-
- if (has_normals)
- nind += vcount;
- }
-
- index += vcount;
- indices += vcount;
- }
- }
-
- mat_prim_map[mp->getMaterialId()].push_back(prim);
- }
-
- geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map;
- }
-
- void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i)
- {
- i *= 3;
-
- switch(arr.getType()) {
- case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
- {
- COLLADAFW::ArrayPrimitiveType<float>* values = arr.getFloatValues();
- if (values->empty()) return;
-
- v[0] = (*values)[i++];
- v[1] = (*values)[i++];
- v[2] = (*values)[i];
- }
- break;
- case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
- {
- COLLADAFW::ArrayPrimitiveType<double>* values = arr.getDoubleValues();
- if (values->empty()) return;
-
- v[0] = (float)(*values)[i++];
- v[1] = (float)(*values)[i++];
- v[2] = (float)(*values)[i];
- }
- break;
- default:
- break;
- }
- }
-
- bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
- {
- float a[3], b[3];
-
- get_vector(a, nor, *nind);
- normalize_v3(a);
-
- nind++;
-
- for (int i = 1; i < count; i++, nind++) {
- get_vector(b, nor, *nind);
- normalize_v3(b);
-
- float dp = dot_v3v3(a, b);
-
- if (dp < 0.99999f || dp > 1.00001f)
- return false;
- }
-
- return true;
- }
-
-public:
-
- MeshImporter(ArmatureImporter *arm, Scene *sce) : scene(sce), armature_importer(arm) {}
-
- virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid)
- {
- if (uid_object_map.find(geom_uid) != uid_object_map.end())
- return uid_object_map[geom_uid];
- return NULL;
- }
-
- MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
- Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
- MTex *color_texture)
- {
- const COLLADAFW::TextureMapId texture_index = ctexture.getTextureMapId();
- const size_t setindex = ctexture.getSetIndex();
- std::string uvname = ctexture.getName();
-
- const CustomData *data = &me->fdata;
- int layer_index = CustomData_get_layer_index(data, CD_MTFACE);
- CustomDataLayer *cdl = &data->layers[layer_index+setindex];
-
- /* set uvname to bind_vertex_input semantic */
- BLI_strncpy(cdl->name, uvname.c_str(), sizeof(cdl->name));
-
- if (texindex_texarray_map.find(texture_index) == texindex_texarray_map.end()) {
-
- fprintf(stderr, "Cannot find texture array by texture index.\n");
- return color_texture;
- }
-
- std::vector<MTex*> textures = texindex_texarray_map[texture_index];
-
- std::vector<MTex*>::iterator it;
-
- for (it = textures.begin(); it != textures.end(); it++) {
-
- MTex *texture = *it;
-
- if (texture) {
- BLI_strncpy(texture->uvname, uvname.c_str(), sizeof(texture->uvname));
- if (texture->mapto == MAP_COL) color_texture = texture;
- }
- }
- return color_texture;
- }
-
- MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
- std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
- Object *ob, const COLLADAFW::UniqueId *geom_uid,
- MTex **color_texture, char *layername, MTFace *texture_face,
- std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index)
- {
- Mesh *me = (Mesh*)ob->data;
- const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
-
- // do we know this material?
- if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
-
- fprintf(stderr, "Cannot find material by UID.\n");
- return NULL;
- }
-
- Material *ma = uid_material_map[ma_uid];
- assign_material(ob, ma, ob->totcol + 1);
-
- COLLADAFW::TextureCoordinateBindingArray& tex_array =
- cmaterial.getTextureCoordinateBindingArray();
- TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma];
- unsigned int i;
- // loop through <bind_vertex_inputs>
- for (i = 0; i < tex_array.getCount(); i++) {
-
- *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
- *color_texture);
- }
-
- // set texture face
- if (*color_texture &&
- strlen((*color_texture)->uvname) &&
- strcmp(layername, (*color_texture)->uvname) != 0) {
-
- texture_face = (MTFace*)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
- (*color_texture)->uvname);
- strcpy(layername, (*color_texture)->uvname);
- }
-
- MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
- COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
-
- // assign material indices to mesh faces
- if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
-
- std::vector<Primitive>& prims = mat_prim_map[mat_id];
-
- std::vector<Primitive>::iterator it;
-
- for (it = prims.begin(); it != prims.end(); it++) {
- Primitive& prim = *it;
- i = 0;
- while (i++ < prim.totface) {
- prim.mface->mat_nr = mat_index;
- prim.mface++;
- // bind texture images to faces
- if (texture_face && (*color_texture)) {
- texture_face->mode = TF_TEX;
- texture_face->tpage = (Image*)(*color_texture)->tex->ima;
- texture_face++;
- }
- }
- }
- }
-
- return texture_face;
- }
-
-
- Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
- bool isController,
- std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
- std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map)
- {
- const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
-
- // check if node instanciates controller or geometry
- if (isController) {
-
- geom_uid = armature_importer->get_geometry_uid(*geom_uid);
-
- if (!geom_uid) {
- fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
- return NULL;
- }
- }
- else {
-
- if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
- // this could happen if a mesh was not created
- // (e.g. if it contains unsupported geometry)
- fprintf(stderr, "Couldn't find a mesh by UID.\n");
- return NULL;
- }
- }
- if (!uid_mesh_map[*geom_uid]) return NULL;
-
- Object *ob = add_object(scene, OB_MESH);
-
- // store object pointer for ArmatureImporter
- uid_object_map[*geom_uid] = ob;
-
- // name Object
- const std::string& id = node->getOriginalId();
- if (id.length())
- rename_id(&ob->id, (char*)id.c_str());
-
- // replace ob->data freeing the old one
- Mesh *old_mesh = (Mesh*)ob->data;
-
- set_mesh(ob, uid_mesh_map[*geom_uid]);
-
- if (old_mesh->id.us == 0) free_libblock(&G.main->mesh, old_mesh);
-
- char layername[100];
- MTFace *texture_face = NULL;
- MTex *color_texture = NULL;
-
- COLLADAFW::MaterialBindingArray& mat_array =
- geom->getMaterialBindings();
-
- // loop through geom's materials
- for (unsigned int i = 0; i < mat_array.getCount(); i++) {
-
- texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid,
- &color_texture, layername, texture_face,
- material_texture_mapping_map, i);
- }
-
- return ob;
- }
-
- // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
- bool write_geometry(const COLLADAFW::Geometry* geom)
- {
- // TODO: import also uvs, normals
- // XXX what to do with normal indices?
- // XXX num_normals may be != num verts, then what to do?
-
- // check geometry->getType() first
- if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
- // TODO: report warning
- fprintf(stderr, "Mesh type %s is not supported\n", geomTypeToStr(geom->getType()));
- return true;
- }
-
- COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh*)geom;
-
- if (!is_nice_mesh(mesh)) {
- fprintf(stderr, "Ignoring mesh %s\n", get_dae_name(mesh));
- return true;
- }
-
- const std::string& str_geom_id = mesh->getOriginalId();
- Mesh *me = add_mesh((char*)str_geom_id.c_str());
-
- // store the Mesh pointer to link it later with an Object
- this->uid_mesh_map[mesh->getUniqueId()] = me;
-
- int new_tris = 0;
-
- read_vertices(mesh, me);
-
- new_tris = count_new_tris(mesh, me);
-
- read_faces(mesh, me, new_tris);
-
- make_edges(me, 0);
-
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
-
- return true;
- }
-
-};
-
-class AnimationImporter : private TransformReader, public AnimationImporterBase
-{
-private:
-
- ArmatureImporter *armature_importer;
- Scene *scene;
-
- std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > curve_map;
- std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map;
- // std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map;
- std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map;
- std::vector<FCurve*> unused_curves;
- std::map<COLLADAFW::UniqueId, Object*> joint_objects;
-
- FCurve *create_fcurve(int array_index, const char *rna_path)
- {
- FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
-
- fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
- fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
- fcu->array_index = array_index;
- return fcu;
- }
-
- void create_bezt(FCurve *fcu, float frame, float output)
- {
- BezTriple bez;
- memset(&bez, 0, sizeof(BezTriple));
- bez.vec[1][0] = frame;
- bez.vec[1][1] = output;
- bez.ipo = U.ipo_new; /* use default interpolation mode here... */
- bez.f1 = bez.f2 = bez.f3 = SELECT;
- bez.h1 = bez.h2 = HD_AUTO;
- insert_bezt_fcurve(fcu, &bez, 0);
- calchandles_fcurve(fcu);
- }
-
- // create one or several fcurves depending on the number of parameters being animated
- void animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
- {
- COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues();
- COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues();
- // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues();
- // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues();
- float fps = (float)FPS;
- size_t dim = curve->getOutDimension();
- unsigned int i;
-
- std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()];
-
- switch (dim) {
- case 1: // X, Y, Z or angle
- case 3: // XYZ
- case 16: // matrix
- {
- for (i = 0; i < dim; i++ ) {
- FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
-
- fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
- // fcu->rna_path = BLI_strdupn(path, strlen(path));
- fcu->array_index = 0;
- //fcu->totvert = curve->getKeyCount();
-
- // create beztriple for each key
- for (unsigned int j = 0; j < curve->getKeyCount(); j++) {
- BezTriple bez;
- memset(&bez, 0, sizeof(BezTriple));
-
- // intangent
- // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps;
- // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1);
-
- // input, output
- bez.vec[1][0] = get_float_value(input, j) * fps;
- bez.vec[1][1] = get_float_value(output, j * dim + i);
-
- // outtangent
- // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps;
- // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1);
-
- bez.ipo = U.ipo_new; /* use default interpolation mode here... */
- bez.f1 = bez.f2 = bez.f3 = SELECT;
- bez.h1 = bez.h2 = HD_AUTO;
- insert_bezt_fcurve(fcu, &bez, 0);
- }
-
- calchandles_fcurve(fcu);
-
- fcurves.push_back(fcu);
- }
- }
- break;
- default:
- fprintf(stderr, "Output dimension of %d is not yet supported (animation id = %s)\n", dim, curve->getOriginalId().c_str());
- }
-
- for (std::vector<FCurve*>::iterator it = fcurves.begin(); it != fcurves.end(); it++)
- unused_curves.push_back(*it);
- }
-
- void fcurve_deg_to_rad(FCurve *cu)
- {
- for (unsigned int i = 0; i < cu->totvert; i++) {
- // TODO convert handles too
- cu->bezt[i].vec[1][1] *= M_PI / 180.0f;
- }
- }
-
- void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated)
- {
- bAction *act;
-
- if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1);
- else act = ob->adt->action;
-
- std::vector<FCurve*>::iterator it;
- int i;
-
-#if 0
- char *p = strstr(rna_path, "rotation_euler");
- bool is_rotation = p && *(p + strlen("rotation_euler")) == '\0';
-
- // convert degrees to radians for rotation
- if (is_rotation)
- fcurve_deg_to_rad(fcu);
-#endif
-
- for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) {
- FCurve *fcu = *it;
- fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
-
- if (array_index == -1) fcu->array_index = i;
- else fcu->array_index = array_index;
-
- if (ob->type == OB_ARMATURE) {
- bActionGroup *grp = NULL;
- const char *bone_name = get_joint_name(animated->node);
-
- if (bone_name) {
- /* try to find group */
- grp = action_groups_find_named(act, bone_name);
-
- /* no matching groups, so add one */
- if (grp == NULL) {
- /* Add a new group, and make it active */
- grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
-
- grp->flag = AGRP_SELECTED;
- BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
-
- BLI_addtail(&act->groups, grp);
- BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
- }
-
- /* add F-Curve to group */
- action_groups_add_channel(act, grp, fcu);
-
- }
-#if 0
- if (is_rotation) {
- fcurves_actionGroup_map[grp].push_back(fcu);
- }
-#endif
- }
- else {
- BLI_addtail(&act->curves, fcu);
- }
-
- // curve is used, so remove it from unused_curves
- unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end());
- }
- }
-public:
-
- AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
- TransformReader(conv), armature_importer(arm), scene(scene) { }
-
- ~AnimationImporter()
- {
- // free unused FCurves
- for (std::vector<FCurve*>::iterator it = unused_curves.begin(); it != unused_curves.end(); it++)
- free_fcurve(*it);
-
- if (unused_curves.size())
- fprintf(stderr, "removed %u unused curves\n", unused_curves.size());
- }
-
- bool write_animation(const COLLADAFW::Animation* anim)
- {
- if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
- COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim;
-
- // XXX Don't know if it's necessary
- // Should we check outPhysicalDimension?
- if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) {
- fprintf(stderr, "Inputs physical dimension is not time. \n");
- return true;
- }
-
- // a curve can have mixed interpolation type,
- // in this case curve->getInterpolationTypes returns a list of interpolation types per key
- COLLADAFW::AnimationCurve::InterpolationType interp = curve->getInterpolationType();
-
- if (interp != COLLADAFW::AnimationCurve::INTERPOLATION_MIXED) {
- switch (interp) {
- case COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR:
- case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER:
- animation_to_fcurves(curve);
- break;
- default:
- // TODO there're also CARDINAL, HERMITE, BSPLINE and STEP types
- fprintf(stderr, "CARDINAL, HERMITE, BSPLINE and STEP anim interpolation types not supported yet.\n");
- break;
- }
- }
- else {
- // not supported yet
- fprintf(stderr, "MIXED anim interpolation type is not supported yet.\n");
- }
- }
- else {
- fprintf(stderr, "FORMULA animation type is not supported yet.\n");
- }
-
- return true;
- }
-
- // called on post-process stage after writeVisualScenes
- bool write_animation_list(const COLLADAFW::AnimationList* animlist)
- {
- const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId();
-
- animlist_map[animlist_id] = animlist;
-
-#if 0
- // should not happen
- if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) {
- return true;
- }
-
- // for bones rna_path is like: pose.bones["bone-name"].rotation
-
- // what does this AnimationList animate?
- Animation& animated = uid_animated_map[animlist_id];
- Object *ob = animated.ob;
-
- char rna_path[100];
- char joint_path[100];
- bool is_joint = false;
-
- // if ob is NULL, it should be a JOINT
- if (!ob) {
- ob = armature_importer->get_armature_for_joint(animated.node);
-
- if (!ob) {
- fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node));
- return true;
- }
-
- armature_importer->get_rna_path_for_joint(animated.node, joint_path, sizeof(joint_path));
-
- is_joint = true;
- }
-
- const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
-
- switch (animated.tm->getTransformationType()) {
- case COLLADAFW::Transformation::TRANSLATE:
- case COLLADAFW::Transformation::SCALE:
- {
- bool loc = animated.tm->getTransformationType() == COLLADAFW::Transformation::TRANSLATE;
- if (is_joint)
- BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale");
- else
- BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path));
-
- for (int i = 0; i < bindings.getCount(); i++) {
- const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
- COLLADAFW::UniqueId anim_uid = binding.animation;
-
- if (curve_map.find(anim_uid) == curve_map.end()) {
- fprintf(stderr, "Cannot find FCurve by animation UID.\n");
- continue;
- }
-
- std::vector<FCurve*>& fcurves = curve_map[anim_uid];
-
- switch (binding.animationClass) {
- case COLLADAFW::AnimationList::POSITION_X:
- add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
- break;
- case COLLADAFW::AnimationList::POSITION_Y:
- add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
- break;
- case COLLADAFW::AnimationList::POSITION_Z:
- add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
- break;
- case COLLADAFW::AnimationList::POSITION_XYZ:
- add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated);
- break;
- default:
- fprintf(stderr, "AnimationClass %d is not supported for %s.\n",
- binding.animationClass, loc ? "TRANSLATE" : "SCALE");
- }
- }
- }
- break;
- case COLLADAFW::Transformation::ROTATE:
- {
- if (is_joint)
- BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path);
- else
- BLI_strncpy(rna_path, "rotation_euler", sizeof(rna_path));
-
- COLLADAFW::Rotate* rot = (COLLADAFW::Rotate*)animated.tm;
- COLLADABU::Math::Vector3& axis = rot->getRotationAxis();
-
- for (int i = 0; i < bindings.getCount(); i++) {
- const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
- COLLADAFW::UniqueId anim_uid = binding.animation;
-
- if (curve_map.find(anim_uid) == curve_map.end()) {
- fprintf(stderr, "Cannot find FCurve by animation UID.\n");
- continue;
- }
-
- std::vector<FCurve*>& fcurves = curve_map[anim_uid];
-
- switch (binding.animationClass) {
- case COLLADAFW::AnimationList::ANGLE:
- if (COLLADABU::Math::Vector3::UNIT_X == axis) {
- add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
- }
- else if (COLLADABU::Math::Vector3::UNIT_Y == axis) {
- add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
- }
- else if (COLLADABU::Math::Vector3::UNIT_Z == axis) {
- add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
- }
- break;
- case COLLADAFW::AnimationList::AXISANGLE:
- // TODO convert axis-angle to quat? or XYZ?
- default:
- fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n",
- binding.animationClass);
- }
- }
- }
- break;
- case COLLADAFW::Transformation::MATRIX:
- case COLLADAFW::Transformation::SKEW:
- case COLLADAFW::Transformation::LOOKAT:
- fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n");
- break;
- }
-#endif
-
- return true;
- }
-
- void read_node_transform(COLLADAFW::Node *node, Object *ob)
- {
- float mat[4][4];
- TransformReader::get_node_mat(mat, node, &uid_animated_map, ob);
- if (ob) {
- copy_m4_m4(ob->obmat, mat);
- object_apply_mat4(ob, ob->obmat);
- }
- }
-
-#if 0
- virtual void change_eul_to_quat(Object *ob, bAction *act)
- {
- bActionGroup *grp;
- int i;
-
- for (grp = (bActionGroup*)act->groups.first; grp; grp = grp->next) {
-
- FCurve *eulcu[3] = {NULL, NULL, NULL};
-
- if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end())
- continue;
-
- std::vector<FCurve*> &rot_fcurves = fcurves_actionGroup_map[grp];
-
- if (rot_fcurves.size() > 3) continue;
-
- for (i = 0; i < rot_fcurves.size(); i++)
- eulcu[rot_fcurves[i]->array_index] = rot_fcurves[i];
-
- char joint_path[100];
- char rna_path[100];
-
- BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name);
- BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path);
-
- FCurve *quatcu[4] = {
- create_fcurve(0, rna_path),
- create_fcurve(1, rna_path),
- create_fcurve(2, rna_path),
- create_fcurve(3, rna_path)
- };
-
- bPoseChannel *chan = get_pose_channel(ob->pose, grp->name);
-
- float m4[4][4], irest[3][3];
- invert_m4_m4(m4, chan->bone->arm_mat);
- copy_m3_m4(irest, m4);
-
- for (i = 0; i < 3; i++) {
-
- FCurve *cu = eulcu[i];
-
- if (!cu) continue;
-
- for (int j = 0; j < cu->totvert; j++) {
- float frame = cu->bezt[j].vec[1][0];
-
- float eul[3] = {
- eulcu[0] ? evaluate_fcurve(eulcu[0], frame) : 0.0f,
- eulcu[1] ? evaluate_fcurve(eulcu[1], frame) : 0.0f,
- eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f
- };
-
- // make eul relative to bone rest pose
- float rot[3][3], rel[3][3], quat[4];
-
- /*eul_to_mat3(rot, eul);
-
- mul_m3_m3m3(rel, irest, rot);
-
- mat3_to_quat(quat, rel);
- */
-
- eul_to_quat(quat, eul);
-
- for (int k = 0; k < 4; k++)
- create_bezt(quatcu[k], frame, quat[k]);
- }
- }
-
- // now replace old Euler curves
-
- for (i = 0; i < 3; i++) {
- if (!eulcu[i]) continue;
-
- action_groups_remove_channel(act, eulcu[i]);
- free_fcurve(eulcu[i]);
- }
-
- chan->rotmode = ROT_MODE_QUAT;
-
- for (i = 0; i < 4; i++)
- action_groups_add_channel(act, grp, quatcu[i]);
- }
-
- bPoseChannel *pchan;
- for (pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->rotmode = ROT_MODE_QUAT;
- }
- }
-#endif
-
- // prerequisites:
- // animlist_map - map animlist id -> animlist
- // curve_map - map anim id -> curve(s)
- Object *translate_animation(COLLADAFW::Node *node,
- std::map<COLLADAFW::UniqueId, Object*>& object_map,
- std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
- COLLADAFW::Transformation::TransformationType tm_type,
- Object *par_job = NULL)
- {
- bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE;
- bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX;
- bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
-
- COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()];
- Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()];
- const char *bone_name = is_joint ? get_joint_name(node) : NULL;
-
- if (!ob) {
- fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str());
- return NULL;
- }
-
- // frames at which to sample
- std::vector<float> frames;
-
- // for each <rotate>, <translate>, etc. there is a separate Transformation
- const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
-
- unsigned int i;
-
- // find frames at which to sample plus convert all rotation keys to radians
- for (i = 0; i < tms.getCount(); i++) {
- COLLADAFW::Transformation *tm = tms[i];
- COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
-
- if (type == tm_type) {
- const COLLADAFW::UniqueId& listid = tm->getAnimationList();
-
- if (animlist_map.find(listid) != animlist_map.end()) {
- const COLLADAFW::AnimationList *animlist = animlist_map[listid];
- const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
-
- if (bindings.getCount()) {
- for (unsigned int j = 0; j < bindings.getCount(); j++) {
- std::vector<FCurve*>& curves = curve_map[bindings[j].animation];
- bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ);
-
- if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3) || is_matrix) {
- std::vector<FCurve*>::iterator iter;
-
- for (iter = curves.begin(); iter != curves.end(); iter++) {
- FCurve *fcu = *iter;
-
- if (is_rotation)
- fcurve_deg_to_rad(fcu);
-
- for (unsigned int k = 0; k < fcu->totvert; k++) {
- float fra = fcu->bezt[k].vec[1][0];
- if (std::find(frames.begin(), frames.end(), fra) == frames.end())
- frames.push_back(fra);
- }
- }
- }
- else {
- fprintf(stderr, "expected %d curves, got %u\n", xyz ? 3 : 1, curves.size());
- }
- }
- }
- }
- }
- }
-
- float irest_dae[4][4];
- float rest[4][4], irest[4][4];
-
- if (is_joint) {
- get_joint_rest_mat(irest_dae, root, node);
- invert_m4(irest_dae);
-
- Bone *bone = get_named_bone((bArmature*)ob->data, bone_name);
- if (!bone) {
- fprintf(stderr, "cannot find bone \"%s\"\n", bone_name);
- return NULL;
- }
-
- unit_m4(rest);
- copy_m4_m4(rest, bone->arm_mat);
- invert_m4_m4(irest, rest);
- }
-
- Object *job = NULL;
-
-#ifdef ARMATURE_TEST
- FCurve *job_curves[10];
- job = get_joint_object(root, node, par_job);
-#endif
-
- if (frames.size() == 0)
- return job;
-
- std::sort(frames.begin(), frames.end());
-
- const char *tm_str = NULL;
- switch (tm_type) {
- case COLLADAFW::Transformation::ROTATE:
- tm_str = "rotation_quaternion";
- break;
- case COLLADAFW::Transformation::SCALE:
- tm_str = "scale";
- break;
- case COLLADAFW::Transformation::TRANSLATE:
- tm_str = "location";
- break;
- case COLLADAFW::Transformation::MATRIX:
- break;
- default:
- return job;
- }
-
- char rna_path[200];
- char joint_path[200];
-
- if (is_joint)
- armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
-
- // new curves
- FCurve *newcu[10]; // if tm_type is matrix, then create 10 curves: 4 rot, 3 loc, 3 scale
- unsigned int totcu = is_matrix ? 10 : (is_rotation ? 4 : 3);
-
- for (i = 0; i < totcu; i++) {
-
- int axis = i;
-
- if (is_matrix) {
- if (i < 4) {
- tm_str = "rotation_quaternion";
- axis = i;
- }
- else if (i < 7) {
- tm_str = "location";
- axis = i - 4;
- }
- else {
- tm_str = "scale";
- axis = i - 7;
- }
- }
-
- if (is_joint)
- BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str);
- else
- strcpy(rna_path, tm_str);
-
- newcu[i] = create_fcurve(axis, rna_path);
-
-#ifdef ARMATURE_TEST
- if (is_joint)
- job_curves[i] = create_fcurve(axis, tm_str);
-#endif
- }
-
- std::vector<float>::iterator it;
-
- // sample values at each frame
- for (it = frames.begin(); it != frames.end(); it++) {
- float fra = *it;
-
- float mat[4][4];
- float matfra[4][4];
-
- unit_m4(matfra);
-
- // calc object-space mat
- evaluate_transform_at_frame(matfra, node, fra);
-
- // for joints, we need a special matrix
- if (is_joint) {
- // special matrix: iR * M * iR_dae * R
- // where R, iR are bone rest and inverse rest mats in world space (Blender bones),
- // iR_dae is joint inverse rest matrix (DAE) and M is an evaluated joint world-space matrix (DAE)
- float temp[4][4], par[4][4];
-
- // calc M
- calc_joint_parent_mat_rest(par, NULL, root, node);
- mul_m4_m4m4(temp, matfra, par);
-
- // evaluate_joint_world_transform_at_frame(temp, NULL, , node, fra);
-
- // calc special matrix
- mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL);
- }
- else {
- copy_m4_m4(mat, matfra);
- }
-
- float val[4], rot[4], loc[3], scale[3];
-
- switch (tm_type) {
- case COLLADAFW::Transformation::ROTATE:
- mat4_to_quat(val, mat);
- break;
- case COLLADAFW::Transformation::SCALE:
- mat4_to_size(val, mat);
- break;
- case COLLADAFW::Transformation::TRANSLATE:
- copy_v3_v3(val, mat[3]);
- break;
- case COLLADAFW::Transformation::MATRIX:
- mat4_to_quat(rot, mat);
- copy_v3_v3(loc, mat[3]);
- mat4_to_size(scale, mat);
- break;
- default:
- break;
- }
-
- // add keys
- for (i = 0; i < totcu; i++) {
- if (is_matrix) {
- if (i < 4)
- add_bezt(newcu[i], fra, rot[i]);
- else if (i < 7)
- add_bezt(newcu[i], fra, loc[i - 4]);
- else
- add_bezt(newcu[i], fra, scale[i - 7]);
- }
- else {
- add_bezt(newcu[i], fra, val[i]);
- }
- }
-
-#ifdef ARMATURE_TEST
- if (is_joint) {
- switch (tm_type) {
- case COLLADAFW::Transformation::ROTATE:
- mat4_to_quat(val, matfra);
- break;
- case COLLADAFW::Transformation::SCALE:
- mat4_to_size(val, matfra);
- break;
- case COLLADAFW::Transformation::TRANSLATE:
- copy_v3_v3(val, matfra[3]);
- break;
- case MATRIX:
- mat4_to_quat(rot, matfra);
- copy_v3_v3(loc, matfra[3]);
- mat4_to_size(scale, matfra);
- break;
- default:
- break;
- }
-
- for (i = 0; i < totcu; i++) {
- if (is_matrix) {
- if (i < 4)
- add_bezt(job_curves[i], fra, rot[i]);
- else if (i < 7)
- add_bezt(job_curves[i], fra, loc[i - 4]);
- else
- add_bezt(job_curves[i], fra, scale[i - 7]);
- }
- else {
- add_bezt(job_curves[i], fra, val[i]);
- }
- }
- }
-#endif
- }
-
- verify_adt_action((ID*)&ob->id, 1);
-
- ListBase *curves = &ob->adt->action->curves;
-
- // add curves
- for (i = 0; i < totcu; i++) {
- if (is_joint)
- add_bone_fcurve(ob, node, newcu[i]);
- else
- BLI_addtail(curves, newcu[i]);
-
-#ifdef ARMATURE_TEST
- if (is_joint)
- BLI_addtail(&job->adt->action->curves, job_curves[i]);
-#endif
- }
-
- if (is_rotation || is_matrix) {
- if (is_joint) {
- bPoseChannel *chan = get_pose_channel(ob->pose, bone_name);
- chan->rotmode = ROT_MODE_QUAT;
- }
- else {
- ob->rotmode = ROT_MODE_QUAT;
- }
- }
-
- return job;
- }
-
- // internal, better make it private
- // warning: evaluates only rotation
- // prerequisites: animlist_map, curve_map
- void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra)
- {
- const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
-
- unit_m4(mat);
-
- for (unsigned int i = 0; i < tms.getCount(); i++) {
- COLLADAFW::Transformation *tm = tms[i];
- COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
- float m[4][4];
-
- unit_m4(m);
-
- if (!evaluate_animation(tm, m, fra, node->getOriginalId().c_str())) {
- switch (type) {
- case COLLADAFW::Transformation::ROTATE:
- dae_rotate_to_mat4(tm, m);
- break;
- case COLLADAFW::Transformation::TRANSLATE:
- dae_translate_to_mat4(tm, m);
- break;
- case COLLADAFW::Transformation::SCALE:
- dae_scale_to_mat4(tm, m);
- break;
- case COLLADAFW::Transformation::MATRIX:
- dae_matrix_to_mat4(tm, m);
- break;
- default:
- fprintf(stderr, "unsupported transformation type %d\n", type);
- }
- }
-
- float temp[4][4];
- copy_m4_m4(temp, mat);
-
- mul_m4_m4m4(mat, m, temp);
- }
- }
-
- // return true to indicate that mat contains a sane value
- bool evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id)
- {
- const COLLADAFW::UniqueId& listid = tm->getAnimationList();
- COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
-
- if (type != COLLADAFW::Transformation::ROTATE &&
- type != COLLADAFW::Transformation::SCALE &&
- type != COLLADAFW::Transformation::TRANSLATE &&
- type != COLLADAFW::Transformation::MATRIX) {
- fprintf(stderr, "animation of transformation %d is not supported yet\n", type);
- return false;
- }
+#include "TransformReader.h"
+#include "AnimationImporter.h"
+#include "ArmatureImporter.h"
+#include "MeshImporter.h"
+#include "collada_utils.h"
- if (animlist_map.find(listid) == animlist_map.end())
- return false;
-
- const COLLADAFW::AnimationList *animlist = animlist_map[listid];
- const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
-
- if (bindings.getCount()) {
- float vec[3];
-
- bool is_scale = (type == COLLADAFW::Transformation::SCALE);
- bool is_translate = (type == COLLADAFW::Transformation::TRANSLATE);
-
- if (type == COLLADAFW::Transformation::SCALE)
- dae_scale_to_v3(tm, vec);
- else if (type == COLLADAFW::Transformation::TRANSLATE)
- dae_translate_to_v3(tm, vec);
-
- for (unsigned int j = 0; j < bindings.getCount(); j++) {
- const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j];
- std::vector<FCurve*>& curves = curve_map[binding.animation];
- COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass;
- char path[100];
-
- switch (type) {
- case COLLADAFW::Transformation::ROTATE:
- BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j);
- break;
- case COLLADAFW::Transformation::SCALE:
- BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j);
- break;
- case COLLADAFW::Transformation::TRANSLATE:
- BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j);
- break;
- case COLLADAFW::Transformation::MATRIX:
- BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j);
- break;
- default:
- break;
- }
-
- if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) {
- fprintf(stderr, "%s: UNKNOWN animation class\n", path);
- continue;
- }
-
- if (type == COLLADAFW::Transformation::ROTATE) {
- if (curves.size() != 1) {
- fprintf(stderr, "expected 1 curve, got %u\n", curves.size());
- return false;
- }
-
- // TODO support other animclasses
- if (animclass != COLLADAFW::AnimationList::ANGLE) {
- fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass);
- return false;
- }
-
- COLLADABU::Math::Vector3& axis = ((COLLADAFW::Rotate*)tm)->getRotationAxis();
- float ax[3] = {axis[0], axis[1], axis[2]};
- float angle = evaluate_fcurve(curves[0], fra);
- axis_angle_to_mat4(mat, ax, angle);
-
- return true;
- }
- else if (is_scale || is_translate) {
- bool is_xyz = animclass == COLLADAFW::AnimationList::POSITION_XYZ;
-
- if ((!is_xyz && curves.size() != 1) || (is_xyz && curves.size() != 3)) {
- if (is_xyz)
- fprintf(stderr, "%s: expected 3 curves, got %u\n", path, curves.size());
- else
- fprintf(stderr, "%s: expected 1 curve, got %u\n", path, curves.size());
- return false;
- }
-
- switch (animclass) {
- case COLLADAFW::AnimationList::POSITION_X:
- vec[0] = evaluate_fcurve(curves[0], fra);
- break;
- case COLLADAFW::AnimationList::POSITION_Y:
- vec[1] = evaluate_fcurve(curves[0], fra);
- break;
- case COLLADAFW::AnimationList::POSITION_Z:
- vec[2] = evaluate_fcurve(curves[0], fra);
- break;
- case COLLADAFW::AnimationList::POSITION_XYZ:
- vec[0] = evaluate_fcurve(curves[0], fra);
- vec[1] = evaluate_fcurve(curves[1], fra);
- vec[2] = evaluate_fcurve(curves[2], fra);
- break;
- default:
- fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass);
- break;
- }
- }
- else if (type == COLLADAFW::Transformation::MATRIX) {
- // for now, of matrix animation, support only the case when all values are packed into one animation
- if (curves.size() != 16) {
- fprintf(stderr, "%s: expected 16 curves, got %u\n", path, curves.size());
- return false;
- }
-
- COLLADABU::Math::Matrix4 matrix;
- int i = 0, j = 0;
-
- for (std::vector<FCurve*>::iterator it = curves.begin(); it != curves.end(); it++) {
- matrix.setElement(i, j, evaluate_fcurve(*it, fra));
- j++;
- if (j == 4) {
- i++;
- j = 0;
- }
- }
-
- COLLADAFW::Matrix tm(matrix);
- dae_matrix_to_mat4(&tm, mat);
-
- return true;
- }
- }
-
- if (is_scale)
- size_to_mat4(mat, vec);
- else
- copy_v3_v3(mat[3], vec);
-
- return is_scale || is_translate;
- }
-
- return false;
- }
-
- // gives a world-space mat of joint at rest position
- void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node)
- {
- // if bind mat is not available,
- // use "current" node transform, i.e. all those tms listed inside <node>
- if (!armature_importer->get_joint_bind_mat(mat, node)) {
- float par[4][4], m[4][4];
-
- calc_joint_parent_mat_rest(par, NULL, root, node);
- get_node_mat(m, node, NULL, NULL);
- mul_m4_m4m4(mat, m, par);
- }
- }
-
- // gives a world-space mat, end's mat not included
- bool calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end)
- {
- float m[4][4];
-
- if (node == end) {
- par ? copy_m4_m4(mat, par) : unit_m4(mat);
- return true;
- }
-
- // use bind matrix if available or calc "current" world mat
- if (!armature_importer->get_joint_bind_mat(m, node)) {
- if (par) {
- float temp[4][4];
- get_node_mat(temp, node, NULL, NULL);
- mul_m4_m4m4(m, temp, par);
- }
- else {
- get_node_mat(m, node, NULL, NULL);
- }
- }
-
- COLLADAFW::NodePointerArray& children = node->getChildNodes();
- for (unsigned int i = 0; i < children.getCount(); i++) {
- if (calc_joint_parent_mat_rest(mat, m, children[i], end))
- return true;
- }
-
- return false;
- }
-
-#ifdef ARMATURE_TEST
- Object *get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job)
- {
- if (joint_objects.find(node->getUniqueId()) == joint_objects.end()) {
- Object *job = add_object(scene, OB_EMPTY);
-
- rename_id((ID*)&job->id, (char*)get_joint_name(node));
-
- job->lay = object_in_scene(job, scene)->lay = 2;
-
- mul_v3_fl(job->size, 0.5f);
- job->recalc |= OB_RECALC_OB;
-
- verify_adt_action((ID*)&job->id, 1);
-
- job->rotmode = ROT_MODE_QUAT;
-
- float mat[4][4];
- get_joint_rest_mat(mat, root, node);
-
- if (par_job) {
- float temp[4][4], ipar[4][4];
- invert_m4_m4(ipar, par_job->obmat);
- copy_m4_m4(temp, mat);
- mul_m4_m4m4(mat, temp, ipar);
- }
-
- TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size);
-
- if (par_job) {
- job->parent = par_job;
-
- par_job->recalc |= OB_RECALC_OB;
- job->parsubstr[0] = 0;
- }
-
- where_is_object(scene, job);
-
- // after parenting and layer change
- DAG_scene_sort(CTX_data_main(C), scene);
-
- joint_objects[node->getUniqueId()] = job;
- }
-
- return joint_objects[node->getUniqueId()];
- }
-#endif
-
-#if 0
- // recursively evaluates joint tree until end is found, mat then is world-space matrix of end
- // mat must be identity on enter, node must be root
- bool evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra)
- {
- float m[4][4];
- if (par) {
- float temp[4][4];
- evaluate_transform_at_frame(temp, node, node == end ? fra : 0.0f);
- mul_m4_m4m4(m, temp, par);
- }
- else {
- evaluate_transform_at_frame(m, node, node == end ? fra : 0.0f);
- }
-
- if (node == end) {
- copy_m4_m4(mat, m);
- return true;
- }
- else {
- COLLADAFW::NodePointerArray& children = node->getChildNodes();
- for (int i = 0; i < children.getCount(); i++) {
- if (evaluate_joint_world_transform_at_frame(mat, m, children[i], end, fra))
- return true;
- }
- }
-
- return false;
- }
-#endif
-
- void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu)
- {
- const char *bone_name = get_joint_name(node);
- bAction *act = ob->adt->action;
-
- /* try to find group */
- bActionGroup *grp = action_groups_find_named(act, bone_name);
-
- /* no matching groups, so add one */
- if (grp == NULL) {
- /* Add a new group, and make it active */
- grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
-
- grp->flag = AGRP_SELECTED;
- BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
-
- BLI_addtail(&act->groups, grp);
- BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
- }
-
- /* add F-Curve to group */
- action_groups_add_channel(act, grp, fcu);
- }
-
- void add_bezt(FCurve *fcu, float fra, float value)
- {
- BezTriple bez;
- memset(&bez, 0, sizeof(BezTriple));
- bez.vec[1][0] = fra;
- bez.vec[1][1] = value;
- bez.ipo = U.ipo_new; /* use default interpolation mode here... */
- bez.f1 = bez.f2 = bez.f3 = SELECT;
- bez.h1 = bez.h2 = HD_AUTO;
- insert_bezt_fcurve(fcu, &bez, 0);
- calchandles_fcurve(fcu);
- }
-};
/*
-
COLLADA Importer limitations:
-
- no multiple scene import, all objects are added to active scene
-
*/
+
+// #define COLLADA_DEBUG
+// creates empties for each imported bone on layer 2, for debugging
+// #define ARMATURE_TEST
+
/** Class that needs to be implemented by a writer.
IMPORTANT: The write functions are called in arbitrary order.*/
class Writer: public COLLADAFW::IWriter
@@ -3468,7 +332,7 @@ public:
else {
new_child = create_instance_node(object_map[child_id], child_node, NULL, sce, is_library_node);
}
- set_parent(new_child, obn, mContext, true);
+ bc_set_parent(new_child, obn, mContext, true);
if (is_library_node)
libnode_ob.push_back(new_child);
@@ -3547,7 +411,7 @@ public:
if (!is_joint) {
// if par was given make this object child of the previous
if (par && ob)
- set_parent(ob, par, mContext);
+ bc_set_parent(ob, par, mContext);
}
// if node has child nodes write them
@@ -3650,8 +514,7 @@ public:
// phong
else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
ma->spec_shader = MA_SPEC_PHONG;
- // XXX setting specular hardness instead of specularity intensity
- ma->har = ef->getShininess().getFloatValue() * 4;
+ ma->har = ef->getShininess().getFloatValue();
}
// lambert
else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index babf8f65d7f..6a6f1dcb3bc 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -21,6 +21,9 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
+#ifndef __DOCUMENTIMPORTER_H__
+#define __DOCUMENTIMPORTER_H__
struct Main;
struct bContext;
@@ -29,3 +32,5 @@ class DocumentImporter
public:
void import(bContext *C, const char *filename);
};
+
+#endif
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
new file mode 100644
index 00000000000..a210eb3b2e0
--- /dev/null
+++ b/source/blender/collada/MeshImporter.cpp
@@ -0,0 +1,907 @@
+/**
+ * $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 "COLLADAFWMeshPrimitive.h"
+#include "COLLADAFWMeshVertexData.h"
+#include "COLLADAFWPolygons.h"
+
+extern "C" {
+#include "BKE_blender.h"
+#include "BKE_customdata.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+}
+
+#include "ArmatureImporter.h"
+#include "MeshImporter.h"
+#include "collada_utils.h"
+
+// works for COLLADAFW::Node, COLLADAFW::Geometry
+template<class T>
+static const char *bc_get_dae_name(T *node)
+{
+ const std::string& name = node->getName();
+ return name.size() ? name.c_str() : node->getOriginalId().c_str();
+}
+
+static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
+{
+ switch (type) {
+ case COLLADAFW::MeshPrimitive::LINES:
+ return "LINES";
+ case COLLADAFW::MeshPrimitive::LINE_STRIPS:
+ return "LINESTRIPS";
+ case COLLADAFW::MeshPrimitive::POLYGONS:
+ return "POLYGONS";
+ case COLLADAFW::MeshPrimitive::POLYLIST:
+ return "POLYLIST";
+ case COLLADAFW::MeshPrimitive::TRIANGLES:
+ return "TRIANGLES";
+ case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
+ return "TRIANGLE_FANS";
+ case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
+ return "TRIANGLE_FANS";
+ case COLLADAFW::MeshPrimitive::POINTS:
+ return "POINTS";
+ case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
+ return "UNDEFINED_PRIMITIVE_TYPE";
+ }
+ return "UNKNOWN";
+}
+
+static const char *bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
+{
+ switch (type) {
+ case COLLADAFW::Geometry::GEO_TYPE_MESH:
+ return "MESH";
+ case COLLADAFW::Geometry::GEO_TYPE_SPLINE:
+ return "SPLINE";
+ case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
+ return "CONVEX_MESH";
+ case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+UVDataWrapper::UVDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata)
+{}
+
+#ifdef COLLADA_DEBUG
+void WVDataWrapper::print()
+{
+ fprintf(stderr, "UVs:\n");
+ switch(mVData->getType()) {
+ case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+ {
+ COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
+ if (values->getCount()) {
+ for (int i = 0; i < values->getCount(); i += 2) {
+ fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i+1]);
+ }
+ }
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+ {
+ COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
+ if (values->getCount()) {
+ for (int i = 0; i < values->getCount(); i += 2) {
+ fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i+1]);
+ }
+ }
+ }
+ break;
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+void UVDataWrapper::getUV(int uv_index[2], float *uv)
+{
+ switch(mVData->getType()) {
+ case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+ {
+ COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
+ if (values->empty()) return;
+ uv[0] = (*values)[uv_index[0]];
+ uv[1] = (*values)[uv_index[1]];
+
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+ {
+ COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
+ if (values->empty()) return;
+ uv[0] = (float)(*values)[uv_index[0]];
+ uv[1] = (float)(*values)[uv_index[1]];
+
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
+ default:
+ fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
+ }
+}
+
+void MeshImporter::set_face_indices(MFace *mface, unsigned int *indices, bool quad)
+{
+ mface->v1 = indices[0];
+ mface->v2 = indices[1];
+ mface->v3 = indices[2];
+ if (quad) mface->v4 = indices[3];
+ else mface->v4 = 0;
+#ifdef COLLADA_DEBUG
+ // fprintf(stderr, "%u, %u, %u \n", indices[0], indices[1], indices[2]);
+#endif
+}
+
+// not used anymore, test_index_face from blenkernel is better
+#if 0
+// change face indices order so that v4 is not 0
+void MeshImporter::rotate_face_indices(MFace *mface) {
+ mface->v4 = mface->v1;
+ mface->v1 = mface->v2;
+ mface->v2 = mface->v3;
+ mface->v3 = 0;
+}
+#endif
+
+void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+ COLLADAFW::IndexList& index_list, unsigned int *tris_indices)
+{
+ int uv_indices[4][2];
+
+ // per face vertex indices, this means for quad we have 4 indices, not 8
+ COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+
+ // make indices into FloatOrDoubleArray
+ for (int i = 0; i < 3; i++) {
+ int uv_index = indices[tris_indices[i]];
+ uv_indices[i][0] = uv_index * 2;
+ uv_indices[i][1] = uv_index * 2 + 1;
+ }
+
+ uvs.getUV(uv_indices[0], mtface->uv[0]);
+ uvs.getUV(uv_indices[1], mtface->uv[1]);
+ uvs.getUV(uv_indices[2], mtface->uv[2]);
+}
+
+void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+ COLLADAFW::IndexList& index_list, int index, bool quad)
+{
+ int uv_indices[4][2];
+
+ // per face vertex indices, this means for quad we have 4 indices, not 8
+ COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+
+ // make indices into FloatOrDoubleArray
+ for (int i = 0; i < (quad ? 4 : 3); i++) {
+ int uv_index = indices[index + i];
+ uv_indices[i][0] = uv_index * 2;
+ uv_indices[i][1] = uv_index * 2 + 1;
+ }
+
+ uvs.getUV(uv_indices[0], mtface->uv[0]);
+ uvs.getUV(uv_indices[1], mtface->uv[1]);
+ uvs.getUV(uv_indices[2], mtface->uv[2]);
+
+ if (quad) uvs.getUV(uv_indices[3], mtface->uv[3]);
+
+#ifdef COLLADA_DEBUG
+ /*if (quad) {
+ fprintf(stderr, "face uv:\n"
+ "((%d, %d), (%d, %d), (%d, %d), (%d, %d))\n"
+ "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
+
+ uv_indices[0][0], uv_indices[0][1],
+ uv_indices[1][0], uv_indices[1][1],
+ uv_indices[2][0], uv_indices[2][1],
+ uv_indices[3][0], uv_indices[3][1],
+
+ mtface->uv[0][0], mtface->uv[0][1],
+ mtface->uv[1][0], mtface->uv[1][1],
+ mtface->uv[2][0], mtface->uv[2][1],
+ mtface->uv[3][0], mtface->uv[3][1]);
+ }
+ else {
+ fprintf(stderr, "face uv:\n"
+ "((%d, %d), (%d, %d), (%d, %d))\n"
+ "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
+
+ uv_indices[0][0], uv_indices[0][1],
+ uv_indices[1][0], uv_indices[1][1],
+ uv_indices[2][0], uv_indices[2][1],
+
+ mtface->uv[0][0], mtface->uv[0][1],
+ mtface->uv[1][0], mtface->uv[1][1],
+ mtface->uv[2][0], mtface->uv[2][1]);
+ }*/
+#endif
+}
+
+#ifdef COLLADA_DEBUG
+void MeshImporter::print_index_list(COLLADAFW::IndexList& index_list)
+{
+ fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str());
+ for (int i = 0; i < index_list.getIndicesCount(); i += 2) {
+ fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1));
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
+{
+ COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+
+ const char *name = bc_get_dae_name(mesh);
+
+ for (unsigned i = 0; i < prim_arr.getCount(); i++) {
+
+ COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+ COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
+
+ const char *type_str = bc_primTypeToStr(type);
+
+ // OpenCollada passes POLYGONS type for <polylist>
+ if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
+
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
+ COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray();
+
+ for(unsigned int j = 0; j < vca.getCount(); j++){
+ int count = vca[j];
+ if (count < 3) {
+ fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n",
+ type_str, name);
+ return false;
+ }
+ }
+
+ }
+ else if(type != COLLADAFW::MeshPrimitive::TRIANGLES) {
+ fprintf(stderr, "Primitive type %s is not supported.\n", type_str);
+ return false;
+ }
+ }
+
+ if (mesh->getPositions().empty()) {
+ fprintf(stderr, "Mesh %s has no vertices.\n", name);
+ return false;
+ }
+
+ return true;
+}
+
+void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
+{
+ // vertices
+ me->totvert = mesh->getPositions().getFloatValues()->getCount() / 3;
+ me->mvert = (MVert*)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+
+ COLLADAFW::MeshVertexData& pos = mesh->getPositions();
+ MVert *mvert;
+ int i;
+
+ for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++)
+ get_vector(mvert->co, pos, i);
+}
+
+int MeshImporter::triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri)
+{
+ ListBase dispbase;
+ DispList *dl;
+ float *vert;
+ int i = 0;
+
+ dispbase.first = dispbase.last = NULL;
+
+ dl = (DispList*)MEM_callocN(sizeof(DispList), "poly disp");
+ dl->nr = totvert;
+ dl->type = DL_POLY;
+ dl->parts = 1;
+ dl->verts = vert = (float*)MEM_callocN(totvert * 3 * sizeof(float), "poly verts");
+ dl->index = (int*)MEM_callocN(sizeof(int) * 3 * totvert, "dl index");
+
+ BLI_addtail(&dispbase, dl);
+
+ for (i = 0; i < totvert; i++) {
+ copy_v3_v3(vert, verts[indices[i]].co);
+ vert += 3;
+ }
+
+ filldisplist(&dispbase, &dispbase, 0);
+
+ int tottri = 0;
+ dl= (DispList*)dispbase.first;
+
+ if (dl->type == DL_INDEX3) {
+ tottri = dl->parts;
+
+ int *index = dl->index;
+ for (i= 0; i < tottri; i++) {
+ int t[3]= {*index, *(index + 1), *(index + 2)};
+
+ std::sort(t, t + 3);
+
+ tri.push_back(t[0]);
+ tri.push_back(t[1]);
+ tri.push_back(t[2]);
+
+ index += 3;
+ }
+ }
+
+ freedisplist(&dispbase);
+
+ return tottri;
+}
+
+int MeshImporter::count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me)
+{
+ COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+ unsigned int i;
+ int tottri = 0;
+
+ for (i = 0; i < prim_arr.getCount(); i++) {
+
+ COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+ int type = mp->getPrimitiveType();
+ size_t prim_totface = mp->getFaceCount();
+ unsigned int *indices = mp->getPositionIndices().getData();
+
+ if (type == COLLADAFW::MeshPrimitive::POLYLIST ||
+ type == COLLADAFW::MeshPrimitive::POLYGONS) {
+
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
+ COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
+
+ for (unsigned int j = 0; j < prim_totface; j++) {
+ int vcount = vcounta[j];
+
+ if (vcount > 4) {
+ std::vector<unsigned int> tri;
+
+ // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?!
+ tottri += triangulate_poly(indices, vcount, me->mvert, tri);
+ }
+
+ indices += vcount;
+ }
+ }
+ }
+ return tottri;
+}
+
+// TODO: import uv set names
+void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris)
+{
+ unsigned int i;
+
+ // allocate faces
+ me->totface = mesh->getFacesCount() + new_tris;
+ me->mface = (MFace*)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+
+ // allocate UV layers
+ unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount();
+
+ for (i = 0; i < totuvset; i++) {
+ if (mesh->getUVCoords().getLength(i) == 0) {
+ totuvset = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < totuvset; i++) {
+ COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i];
+ CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str());
+ //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
+ }
+
+ // activate the first uv layer
+ if (totuvset) me->mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0);
+
+ UVDataWrapper uvs(mesh->getUVCoords());
+
+#ifdef COLLADA_DEBUG
+ // uvs.print();
+#endif
+
+ MFace *mface = me->mface;
+
+ MaterialIdPrimitiveArrayMap mat_prim_map;
+
+ int face_index = 0;
+
+ COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+
+ bool has_normals = mesh->hasNormals();
+ COLLADAFW::MeshVertexData& nor = mesh->getNormals();
+
+ for (i = 0; i < prim_arr.getCount(); i++) {
+
+ COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+
+ // faces
+ size_t prim_totface = mp->getFaceCount();
+ unsigned int *indices = mp->getPositionIndices().getData();
+ unsigned int *nind = mp->getNormalIndices().getData();
+ unsigned int j, k;
+ int type = mp->getPrimitiveType();
+ int index = 0;
+
+ // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive
+ Primitive prim = {mface, 0};
+ COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray();
+
+#ifdef COLLADA_DEBUG
+ /*
+ fprintf(stderr, "Primitive %d:\n", i);
+ for (int j = 0; j < totuvset; j++) {
+ print_index_list(*index_list_array[j]);
+ }
+ */
+#endif
+
+ if (type == COLLADAFW::MeshPrimitive::TRIANGLES) {
+ for (j = 0; j < prim_totface; j++){
+
+ set_face_indices(mface, indices, false);
+ indices += 3;
+
+#if 0
+ for (k = 0; k < totuvset; k++) {
+ if (!index_list_array.empty() && index_list_array[k]) {
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+ set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false);
+ }
+ }
+#else
+ for (k = 0; k < index_list_array.getCount(); k++) {
+ int uvset_index = index_list_array[k]->getSetIndex();
+
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
+ set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false);
+ }
+#endif
+
+ test_index_face(mface, &me->fdata, face_index, 3);
+
+ if (has_normals) {
+ if (!flat_face(nind, nor, 3))
+ mface->flag |= ME_SMOOTH;
+
+ nind += 3;
+ }
+
+ index += 3;
+ mface++;
+ face_index++;
+ prim.totface++;
+ }
+ }
+ else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
+ COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
+
+ for (j = 0; j < prim_totface; j++) {
+
+ // face
+ int vcount = vcounta[j];
+ if (vcount == 3 || vcount == 4) {
+
+ set_face_indices(mface, indices, vcount == 4);
+
+ // set mtface for each uv set
+ // it is assumed that all primitives have equal number of UV sets
+
+#if 0
+ for (k = 0; k < totuvset; k++) {
+ if (!index_list_array.empty() && index_list_array[k]) {
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+ set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0);
+ }
+ }
+#else
+ for (k = 0; k < index_list_array.getCount(); k++) {
+ int uvset_index = index_list_array[k]->getSetIndex();
+
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
+ set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, mface->v4 != 0);
+ }
+#endif
+
+ test_index_face(mface, &me->fdata, face_index, vcount);
+
+ if (has_normals) {
+ if (!flat_face(nind, nor, vcount))
+ mface->flag |= ME_SMOOTH;
+
+ nind += vcount;
+ }
+
+ mface++;
+ face_index++;
+ prim.totface++;
+
+ }
+ else {
+ std::vector<unsigned int> tri;
+
+ triangulate_poly(indices, vcount, me->mvert, tri);
+
+ for (k = 0; k < tri.size() / 3; k++) {
+ int v = k * 3;
+ unsigned int uv_indices[3] = {
+ index + tri[v],
+ index + tri[v + 1],
+ index + tri[v + 2]
+ };
+ unsigned int tri_indices[3] = {
+ indices[tri[v]],
+ indices[tri[v + 1]],
+ indices[tri[v + 2]]
+ };
+
+ set_face_indices(mface, tri_indices, false);
+
+#if 0
+ for (unsigned int l = 0; l < totuvset; l++) {
+ if (!index_list_array.empty() && index_list_array[l]) {
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l);
+ set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices);
+ }
+ }
+#else
+ for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
+ int uvset_index = index_list_array[l]->getSetIndex();
+
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
+ set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices);
+ }
+#endif
+
+
+ test_index_face(mface, &me->fdata, face_index, 3);
+
+ if (has_normals) {
+ unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]};
+
+ if (!flat_face(ntri, nor, 3))
+ mface->flag |= ME_SMOOTH;
+ }
+
+ mface++;
+ face_index++;
+ prim.totface++;
+ }
+
+ if (has_normals)
+ nind += vcount;
+ }
+
+ index += vcount;
+ indices += vcount;
+ }
+ }
+
+ mat_prim_map[mp->getMaterialId()].push_back(prim);
+ }
+
+ geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map;
+}
+
+void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i)
+{
+ i *= 3;
+
+ switch(arr.getType()) {
+ case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+ {
+ COLLADAFW::ArrayPrimitiveType<float>* values = arr.getFloatValues();
+ if (values->empty()) return;
+
+ v[0] = (*values)[i++];
+ v[1] = (*values)[i++];
+ v[2] = (*values)[i];
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+ {
+ COLLADAFW::ArrayPrimitiveType<double>* values = arr.getDoubleValues();
+ if (values->empty()) return;
+
+ v[0] = (float)(*values)[i++];
+ v[1] = (float)(*values)[i++];
+ v[2] = (float)(*values)[i];
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
+{
+ float a[3], b[3];
+
+ get_vector(a, nor, *nind);
+ normalize_v3(a);
+
+ nind++;
+
+ for (int i = 1; i < count; i++, nind++) {
+ get_vector(b, nor, *nind);
+ normalize_v3(b);
+
+ float dp = dot_v3v3(a, b);
+
+ if (dp < 0.99999f || dp > 1.00001f)
+ return false;
+ }
+
+ return true;
+}
+
+MeshImporter::MeshImporter(ArmatureImporter *arm, Scene *sce) : scene(sce), armature_importer(arm) {}
+
+Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid)
+{
+ if (uid_object_map.find(geom_uid) != uid_object_map.end())
+ return uid_object_map[geom_uid];
+ return NULL;
+}
+
+MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
+ Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
+ MTex *color_texture)
+{
+ const COLLADAFW::TextureMapId texture_index = ctexture.getTextureMapId();
+ const size_t setindex = ctexture.getSetIndex();
+ std::string uvname = ctexture.getName();
+
+ const CustomData *data = &me->fdata;
+ int layer_index = CustomData_get_layer_index(data, CD_MTFACE);
+ CustomDataLayer *cdl = &data->layers[layer_index+setindex];
+
+ /* set uvname to bind_vertex_input semantic */
+ BLI_strncpy(cdl->name, uvname.c_str(), sizeof(cdl->name));
+
+ if (texindex_texarray_map.find(texture_index) == texindex_texarray_map.end()) {
+
+ fprintf(stderr, "Cannot find texture array by texture index.\n");
+ return color_texture;
+ }
+
+ std::vector<MTex*> textures = texindex_texarray_map[texture_index];
+
+ std::vector<MTex*>::iterator it;
+
+ for (it = textures.begin(); it != textures.end(); it++) {
+
+ MTex *texture = *it;
+
+ if (texture) {
+ BLI_strncpy(texture->uvname, uvname.c_str(), sizeof(texture->uvname));
+ if (texture->mapto == MAP_COL) color_texture = texture;
+ }
+ }
+ return color_texture;
+}
+
+MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+ Object *ob, const COLLADAFW::UniqueId *geom_uid,
+ MTex **color_texture, char *layername, MTFace *texture_face,
+ std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index)
+{
+ Mesh *me = (Mesh*)ob->data;
+ const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
+
+ // do we know this material?
+ if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
+
+ fprintf(stderr, "Cannot find material by UID.\n");
+ return NULL;
+ }
+
+ Material *ma = uid_material_map[ma_uid];
+ assign_material(ob, ma, ob->totcol + 1);
+
+ COLLADAFW::TextureCoordinateBindingArray& tex_array =
+ cmaterial.getTextureCoordinateBindingArray();
+ TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma];
+ unsigned int i;
+ // loop through <bind_vertex_inputs>
+ for (i = 0; i < tex_array.getCount(); i++) {
+
+ *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
+ *color_texture);
+ }
+
+ // set texture face
+ if (*color_texture &&
+ strlen((*color_texture)->uvname) &&
+ strcmp(layername, (*color_texture)->uvname) != 0) {
+
+ texture_face = (MTFace*)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
+ (*color_texture)->uvname);
+ strcpy(layername, (*color_texture)->uvname);
+ }
+
+ MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
+ COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
+
+ // assign material indices to mesh faces
+ if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
+
+ std::vector<Primitive>& prims = mat_prim_map[mat_id];
+
+ std::vector<Primitive>::iterator it;
+
+ for (it = prims.begin(); it != prims.end(); it++) {
+ Primitive& prim = *it;
+ i = 0;
+ while (i++ < prim.totface) {
+ prim.mface->mat_nr = mat_index;
+ prim.mface++;
+ // bind texture images to faces
+ if (texture_face && (*color_texture)) {
+ texture_face->mode = TF_TEX;
+ texture_face->tpage = (Image*)(*color_texture)->tex->ima;
+ texture_face++;
+ }
+ }
+ }
+ }
+
+ return texture_face;
+}
+
+
+Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
+ bool isController,
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+ std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map)
+{
+ const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
+
+ // check if node instanciates controller or geometry
+ if (isController) {
+
+ geom_uid = armature_importer->get_geometry_uid(*geom_uid);
+
+ if (!geom_uid) {
+ fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
+ return NULL;
+ }
+ }
+ else {
+
+ if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
+ // this could happen if a mesh was not created
+ // (e.g. if it contains unsupported geometry)
+ fprintf(stderr, "Couldn't find a mesh by UID.\n");
+ return NULL;
+ }
+ }
+ if (!uid_mesh_map[*geom_uid]) return NULL;
+
+ Object *ob = add_object(scene, OB_MESH);
+
+ // store object pointer for ArmatureImporter
+ uid_object_map[*geom_uid] = ob;
+
+ // name Object
+ const std::string& id = node->getOriginalId();
+ if (id.length())
+ rename_id(&ob->id, (char*)id.c_str());
+
+ // replace ob->data freeing the old one
+ Mesh *old_mesh = (Mesh*)ob->data;
+
+ set_mesh(ob, uid_mesh_map[*geom_uid]);
+
+ if (old_mesh->id.us == 0) free_libblock(&G.main->mesh, old_mesh);
+
+ char layername[100];
+ MTFace *texture_face = NULL;
+ MTex *color_texture = NULL;
+
+ COLLADAFW::MaterialBindingArray& mat_array =
+ geom->getMaterialBindings();
+
+ // loop through geom's materials
+ for (unsigned int i = 0; i < mat_array.getCount(); i++) {
+
+ texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid,
+ &color_texture, layername, texture_face,
+ material_texture_mapping_map, i);
+ }
+
+ return ob;
+}
+
+// create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
+bool MeshImporter::write_geometry(const COLLADAFW::Geometry* geom)
+{
+ // TODO: import also uvs, normals
+ // XXX what to do with normal indices?
+ // XXX num_normals may be != num verts, then what to do?
+
+ // check geometry->getType() first
+ if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
+ // TODO: report warning
+ fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
+ return true;
+ }
+
+ COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh*)geom;
+
+ if (!is_nice_mesh(mesh)) {
+ fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh));
+ return true;
+ }
+
+ const std::string& str_geom_id = mesh->getOriginalId();
+ Mesh *me = add_mesh((char*)str_geom_id.c_str());
+
+ // store the Mesh pointer to link it later with an Object
+ this->uid_mesh_map[mesh->getUniqueId()] = me;
+
+ int new_tris = 0;
+
+ read_vertices(mesh, me);
+
+ new_tris = count_new_tris(mesh, me);
+
+ read_faces(mesh, me, new_tris);
+
+ make_edges(me, 0);
+
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+ return true;
+}
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
new file mode 100644
index 00000000000..8c468b01fb6
--- /dev/null
+++ b/source/blender/collada/MeshImporter.h
@@ -0,0 +1,150 @@
+/**
+ * $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 *****
+ */
+
+#ifndef __BC__MESHIMPORTER_H__
+#define __BC__MESHIMPORTER_H__
+
+#include <map>
+#include <vector>
+
+#include "COLLADAFWIndexList.h"
+#include "COLLADAFWInstanceGeometry.h"
+#include "COLLADAFWMaterialBinding.h"
+#include "COLLADAFWMesh.h"
+#include "COLLADAFWMeshVertexData.h"
+#include "COLLADAFWNode.h"
+#include "COLLADAFWTextureCoordinateBinding.h"
+#include "COLLADAFWTypes.h"
+#include "COLLADAFWUniqueId.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "ArmatureImporter.h"
+#include "collada_utils.h"
+
+// only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid
+class MeshImporterBase
+{
+public:
+ virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0;
+};
+
+class UVDataWrapper
+{
+ COLLADAFW::MeshVertexData *mVData;
+public:
+ UVDataWrapper(COLLADAFW::MeshVertexData& vdata);
+
+#ifdef COLLADA_DEBUG
+ void print();
+#endif
+
+ void getUV(int uv_index[2], float *uv);
+};
+
+class MeshImporter : public MeshImporterBase
+{
+private:
+
+ Scene *scene;
+ ArmatureImporter *armature_importer;
+
+ std::map<COLLADAFW::UniqueId, Mesh*> uid_mesh_map; // geometry unique id-to-mesh map
+ std::map<COLLADAFW::UniqueId, Object*> uid_object_map; // geom uid-to-object
+ // this structure is used to assign material indices to faces
+ // it holds a portion of Mesh faces and corresponds to a DAE primitive list (<triangles>, <polylist>, etc.)
+ struct Primitive {
+ MFace *mface;
+ unsigned int totface;
+ };
+ typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap;
+ std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name!
+
+
+ void set_face_indices(MFace *mface, unsigned int *indices, bool quad);
+
+ // not used anymore, test_index_face from blenkernel is better
+#if 0
+ // change face indices order so that v4 is not 0
+ void rotate_face_indices(MFace *mface);
+#endif
+
+ void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+ COLLADAFW::IndexList& index_list, unsigned int *tris_indices);
+
+ void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+ COLLADAFW::IndexList& index_list, int index, bool quad);
+
+#ifdef COLLADA_DEBUG
+ void print_index_list(COLLADAFW::IndexList& index_list);
+#endif
+
+ bool is_nice_mesh(COLLADAFW::Mesh *mesh);
+
+ void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
+
+ int triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri);
+
+ int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me);
+
+ // TODO: import uv set names
+ void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris);
+
+ void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i);
+
+ bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count);
+
+public:
+
+ MeshImporter(ArmatureImporter *arm, Scene *sce);
+
+ virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid);
+
+ MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
+ Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
+ MTex *color_texture);
+
+ MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+ Object *ob, const COLLADAFW::UniqueId *geom_uid,
+ MTex **color_texture, char *layername, MTFace *texture_face,
+ std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index);
+
+
+ Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
+ bool isController,
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+ std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map);
+
+ // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
+ bool write_geometry(const COLLADAFW::Geometry* geom);
+
+};
+
+#endif
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
diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h
new file mode 100644
index 00000000000..b7b87494be6
--- /dev/null
+++ b/source/blender/collada/SkinInfo.h
@@ -0,0 +1,133 @@
+/**
+ * $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 *****
+ */
+
+#ifndef __BC_SKININFO_H__
+#define __BC_SKININFO_H__
+
+#include <map>
+#include <vector>
+
+#include "COLLADAFWUniqueId.h"
+#include "COLLADAFWTypes.h"
+#include "COLLADAFWNode.h"
+#include "COLLADAFWSkinController.h"
+#include "COLLADAFWSkinControllerData.h"
+
+#include "DNA_object_types.h"
+#include "BKE_context.h"
+
+#include "TransformReader.h"
+#include "collada_internal.h"
+
+// 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.
+class SkinInfo
+{
+private:
+ // to build armature bones from inverse bind matrices
+ struct JointData {
+ float inv_bind_mat[4][4]; // joint inverse bind matrix
+ COLLADAFW::UniqueId joint_uid; // joint node UID
+ // Object *ob_arm; // armature object
+ };
+
+ float bind_shape_matrix[4][4];
+
+ // data from COLLADAFW::SkinControllerData, each array should be freed
+ COLLADAFW::UIntValuesArray joints_per_vertex;
+ COLLADAFW::UIntValuesArray weight_indices;
+ COLLADAFW::IntValuesArray joint_indices;
+ // COLLADAFW::FloatOrDoubleArray weights;
+ std::vector<float> weights;
+
+ std::vector<JointData> joint_data; // index to this vector is joint index
+
+ UnitConverter *unit_converter;
+
+ Object *ob_arm;
+ COLLADAFW::UniqueId controller_uid;
+ Object *parent;
+
+public:
+
+ SkinInfo();
+ SkinInfo(const SkinInfo& skin);
+ SkinInfo(UnitConverter *conv);
+
+ // nobody owns the data after this, so it should be freed manually with releaseMemory
+ template <typename T>
+ void transfer_array_data(T& src, T& dest);
+
+ // when src is const we cannot src.yieldOwnerShip, this is used by copy constructor
+ void transfer_int_array_data_const(const COLLADAFW::IntValuesArray& src, COLLADAFW::IntValuesArray& dest);
+
+ void transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest);
+
+ void borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin);
+
+ void free();
+
+ // 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 add_joint(const COLLADABU::Math::Matrix4& matrix);
+
+ void set_controller(const COLLADAFW::SkinController* co);
+
+ // called from write_controller
+ Object *create_armature(Scene *scene);
+
+ Object* set_armature(Object *ob_arm);
+
+ bool get_joint_inv_bind_matrix(float inv_bind_mat[][4], COLLADAFW::Node *node);
+
+ Object *get_armature();
+
+ const COLLADAFW::UniqueId& get_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 uses_joint_or_descendant(COLLADAFW::Node *node);
+
+ void link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, TransformReader *tm);
+
+ bPoseChannel *get_pose_channel_from_node(COLLADAFW::Node *node);
+
+ void set_parent(Object *_parent);
+
+ Object* get_parent();
+
+ void find_root_joints(const std::vector<COLLADAFW::Node*> &root_joints,
+ std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid,
+ std::vector<COLLADAFW::Node*>& result);
+
+ bool find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root);
+
+};
+
+#endif \ No newline at end of file
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
new file mode 100644
index 00000000000..d951bfb6474
--- /dev/null
+++ b/source/blender/collada/TransformReader.cpp
@@ -0,0 +1,125 @@
+/**
+ * $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 "TransformReader.h"
+
+TransformReader::TransformReader(UnitConverter* conv) : unit_converter(conv) {}
+
+void TransformReader::get_node_mat(float mat[][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob)
+{
+ float cur[4][4];
+ float copy[4][4];
+
+ unit_m4(mat);
+
+ for (unsigned int i = 0; i < node->getTransformations().getCount(); i++) {
+
+ COLLADAFW::Transformation *tm = node->getTransformations()[i];
+ COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
+
+ switch(type) {
+ case COLLADAFW::Transformation::TRANSLATE:
+ dae_translate_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::ROTATE:
+ dae_rotate_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ dae_scale_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::MATRIX:
+ dae_matrix_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::LOOKAT:
+ case COLLADAFW::Transformation::SKEW:
+ fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
+ break;
+ }
+
+ copy_m4_m4(copy, mat);
+ mul_m4_m4m4(mat, cur, copy);
+
+ if (animation_map) {
+ // AnimationList that drives this Transformation
+ const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList();
+
+ // store this so later we can link animation data with ob
+ Animation anim = {ob, node, tm};
+ (*animation_map)[anim_list_id] = anim;
+ }
+ }
+}
+
+void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
+{
+ COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm;
+ COLLADABU::Math::Vector3& axis = ro->getRotationAxis();
+ float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f);
+ float ax[] = {axis[0], axis[1], axis[2]};
+ // float quat[4];
+ // axis_angle_to_quat(quat, axis, angle);
+ // quat_to_mat4(m, quat);
+ axis_angle_to_mat4(m, ax, angle);
+}
+
+void TransformReader::dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
+{
+ COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm;
+ COLLADABU::Math::Vector3& t = tra->getTranslation();
+
+ unit_m4(m);
+
+ m[3][0] = (float)t[0];
+ m[3][1] = (float)t[1];
+ m[3][2] = (float)t[2];
+}
+
+void TransformReader::dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
+{
+ COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale();
+ float size[3] = {(float)s[0], (float)s[1], (float)s[2]};
+ size_to_mat4(m, size);
+}
+
+void TransformReader::dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4])
+{
+ unit_converter->dae_matrix_to_mat4_(m, ((COLLADAFW::Matrix*)tm)->getMatrix());
+}
+
+void TransformReader::dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3])
+{
+ dae_vector3_to_v3(((COLLADAFW::Translate*)tm)->getTranslation(), v);
+}
+
+void TransformReader::dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3])
+{
+ dae_vector3_to_v3(((COLLADAFW::Scale*)tm)->getScale(), v);
+}
+
+void TransformReader::dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3])
+{
+ v[0] = v3.x;
+ v[1] = v3.y;
+ v[2] = v3.z;
+} \ No newline at end of file
diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h
new file mode 100644
index 00000000000..fa08df1d4fa
--- /dev/null
+++ b/source/blender/collada/TransformReader.h
@@ -0,0 +1,70 @@
+/**
+ * $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 *****
+ */
+
+#ifndef __BC_TRANSFORMREADER_H__
+#define __BC_TRANSFORMREADER_H__
+
+#include "COLLADAFWNode.h"
+#include "COLLADAFWTransformation.h"
+#include "COLLADAFWTranslate.h"
+#include "COLLADAFWRotate.h"
+#include "COLLADAFWScale.h"
+#include "COLLADAFWMatrix.h"
+#include "COLLADAFWUniqueId.h"
+#include "Math/COLLADABUMathVector3.h"
+
+#include "DNA_object_types.h"
+#include "BLI_math.h"
+
+#include "collada_internal.h"
+
+//struct Object;
+
+class TransformReader : public TransformBase
+{
+protected:
+
+ UnitConverter *unit_converter;
+
+public:
+ struct Animation {
+ Object *ob;
+ COLLADAFW::Node *node;
+ COLLADAFW::Transformation *tm; // which transform is animated by an AnimationList->id
+ };
+
+ TransformReader(UnitConverter* conv);
+
+ void get_node_mat(float mat[][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob);
+
+ void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]);
+ void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]);
+ void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4]);
+ void dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4]);
+ void dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3]);
+ void dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3]);
+ void dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3]);
+};
+
+#endif \ No newline at end of file
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index a519db3332c..d499249cfa2 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -21,15 +21,15 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#include "BKE_main.h"
-#include "BKE_scene.h"
-#include "BKE_context.h"
#include "DocumentExporter.h"
#include "DocumentImporter.h"
extern "C"
{
+#include "BKE_scene.h"
+#include "BKE_context.h"
+
int collada_import(bContext *C, const char *filepath)
{
DocumentImporter imp;
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index 242fce749c4..f8fbe71e6d9 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -27,6 +27,8 @@
#include "COLLADAFWFileInfo.h"
#include "Math/COLLADABUMathMatrix4.h"
+#include "BLI_math.h"
+
class UnitConverter
{
private:
@@ -35,6 +37,7 @@ private:
public:
+ // Initialize with Z_UP, since Blender uses right-handed, z-up
UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP) {}
void read_asset(const COLLADAFW::FileInfo* asset)
@@ -49,7 +52,7 @@ public:
// TODO need also for angle conversion, time conversion...
- void dae_matrix_to_mat4(float out[][4], const COLLADABU::Math::Matrix4& in)
+ void dae_matrix_to_mat4_(float out[][4], const COLLADABU::Math::Matrix4& in)
{
// in DAE, matrices use columns vectors, (see comments in COLLADABUMathMatrix4.h)
// so here, to make a blender matrix, we swap columns and rows
@@ -84,10 +87,12 @@ public:
void decompose(float mat[][4], float *loc, float eul[3], float quat[4], float *size)
{
mat4_to_size(size, mat);
- if (eul)
+ if (eul) {
mat4_to_eul(eul, mat);
- if (quat)
+ }
+ if (quat) {
mat4_to_quat(quat, mat);
+ }
copy_v3_v3(loc, mat[3]);
}
};
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
new file mode 100644
index 00000000000..ec0bc91ee0b
--- /dev/null
+++ b/source/blender/collada/collada_utils.cpp
@@ -0,0 +1,106 @@
+/**
+ * $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 "COLLADAFWGeometry.h"
+#include "COLLADAFWMeshPrimitive.h"
+#include "COLLADAFWMeshVertexData.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+
+#include "WM_api.h" // XXX hrm, see if we can do without this
+#include "WM_types.h"
+
+float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
+{
+ if (index >= array.getValuesCount())
+ return 0.0f;
+
+ if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
+ return array.getFloatValues()->getData()[index];
+ else
+ return array.getDoubleValues()->getData()[index];
+}
+
+// copied from /editors/object/object_relations.c
+int bc_test_parent_loop(Object *par, Object *ob)
+{
+ /* test if 'ob' is a parent somewhere in par's parents */
+
+ if(par == NULL) return 0;
+ if(ob == par) return 1;
+
+ return bc_test_parent_loop(par->parent, ob);
+}
+
+// a shortened version of parent_set_exec()
+// if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting
+int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
+{
+ Object workob;
+ Main *bmain = CTX_data_main(C);
+ Scene *sce = CTX_data_scene(C);
+
+ if (!par || bc_test_parent_loop(par, ob))
+ return false;
+
+ ob->parent = par;
+ ob->partype = PAROBJECT;
+
+ ob->parsubstr[0] = 0;
+
+ if (is_parent_space) {
+ float mat[4][4];
+ // calc par->obmat
+ where_is_object(sce, par);
+
+ // move child obmat into world space
+ mul_m4_m4m4(mat, ob->obmat, par->obmat);
+ copy_m4_m4(ob->obmat, mat);
+ }
+
+ // apply child obmat (i.e. decompose it into rot/loc/size)
+ object_apply_mat4(ob, ob->obmat);
+
+ // compute parentinv
+ what_does_parent(sce, ob, &workob);
+ invert_m4_m4(ob->parentinv, workob.obmat);
+
+ ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA;
+ par->recalc |= OB_RECALC_OB;
+
+ DAG_scene_sort(bmain, sce);
+ DAG_ids_flush_update(bmain, 0);
+ WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
+
+ return true;
+}
+
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
new file mode 100644
index 00000000000..dbcbfdafec8
--- /dev/null
+++ b/source/blender/collada/collada_utils.h
@@ -0,0 +1,50 @@
+/**
+ * $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 *****
+ */
+
+#ifndef __BC_UTILS_H__
+#define __BC_UTILS_H__
+
+#include "COLLADAFWMeshPrimitive.h"
+#include "COLLADAFWGeometry.h"
+#include "COLLADAFWFloatOrDoubleArray.h"
+#include "COLLADAFWTypes.h"
+
+#include <vector>
+#include <map>
+
+#include "DNA_object_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_texture_types.h"
+#include "BKE_context.h"
+
+typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex*> > TexIndexTextureArrayMap;
+
+extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index);
+
+extern int bc_test_parent_loop(Object *par, Object *ob);
+extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space=true);
+extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int n);
+extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type);
+
+#endif
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 6055b9eecb3..474b50540d8 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -27,6 +27,10 @@
#ifndef ED_ARMATURE_H
#define ED_ARMATURE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bArmature;
struct Base;
struct bContext;
@@ -168,6 +172,10 @@ int BDR_drawSketchNames(struct ViewContext *vc);
void mesh_deform_bind(struct Scene *scene,
struct MeshDeformModifierData *mmd,
float *vertexcos, int totvert, float cagemat[][4]);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* ED_ARMATURE_H */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 8718d39dd18..b3aac489852 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -28,6 +28,10 @@
#ifndef ED_KEYFRAMING_H
#define ED_KEYFRAMING_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ListBase;
struct ID;
struct Scene;
@@ -280,4 +284,8 @@ typedef enum eAnimFilterFlags {
ANIMFILTER_KEYS_NOSKEY = (1<<10), /* don't include shape keys (for geometry) */
} eAnimFilterFlags;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ED_KEYFRAMING_H */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 564fe04ca4d..c4477ee5a8e 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -28,6 +28,10 @@
#ifndef ED_MESH_H
#define ED_MESH_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ID;
struct View3D;
struct ARegion;
@@ -224,5 +228,9 @@ int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh
int ED_mesh_color_add(struct bContext *C, struct Scene *scene, struct Object *ob, struct Mesh *me, const char *name, int active_set);
int ED_mesh_color_remove(struct bContext *C, struct Object *ob, struct Mesh *me);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ED_MESH_H */
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index f243b4cc497..64e72a5e2fa 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -28,6 +28,10 @@
#ifndef ED_OBJECT_H
#define ED_OBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Base;
struct bConstraint;
struct bContext;
@@ -141,5 +145,9 @@ int ED_object_modifier_convert(struct ReportList *reports, struct Main *bmain, s
int ED_object_modifier_apply(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md, int mode);
int ED_object_modifier_copy(struct ReportList *reports, struct Object *ob, struct ModifierData *md);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ED_OBJECT_H */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 8908143946a..6c0b4db221d 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -30,6 +30,10 @@
#ifndef DNA_CUSTOMDATA_TYPES_H
#define DNA_CUSTOMDATA_TYPES_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* descriptor and storage for a custom data layer */
typedef struct CustomDataLayer {
int type; /* type of data in layer */
@@ -128,4 +132,8 @@ typedef struct CustomData {
#define MAX_MTFACE 8
#define MAX_MCOL 8
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index e9e058cbbd6..19aacaa8108 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -34,6 +34,10 @@
#include "DNA_ID.h"
#include "DNA_image_types.h" /* ImageUser */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct Ipo;
struct PluginTex;
@@ -554,5 +558,9 @@ typedef struct TexMapping {
#define TEX_VD_SMOKEHEAT 1
#define TEX_VD_SMOKEVEL 2
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 52e82eb743d..4e3a957d775 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -35,6 +35,10 @@
#include "DNA_listBase.h"
#include "DNA_texture_types.h" /* ColorBand */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* themes; defines in BIF_resource.h */
struct ColorBand;
@@ -558,4 +562,8 @@ extern UserDef U; /* from blenkernel blender.c */
#define TH_OLDSKOOL 3
#define TH_SHADED 4
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 93b38499673..d6964f5d569 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -44,10 +44,10 @@ EnumPropertyItem region_type_items[] = {
{RGN_TYPE_PREVIEW, "PREVIEW", 0, "Preview", ""},
{0, NULL, 0, NULL, NULL}};
-#ifdef RNA_RUNTIME
-
#include "ED_screen.h"
+#ifdef RNA_RUNTIME
+
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 690d8ad0f75..f103cbe2d4e 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -31,6 +31,10 @@
/* dna-savable wmStructs here */
#include "DNA_windowmanager_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bContext;
struct IDProperty;
struct wmEvent;
@@ -338,5 +342,9 @@ void WM_clipboard_text_set(char *buf, int selection);
void WM_progress_set(struct wmWindow *win, float progress);
void WM_progress_clear(struct wmWindow *win);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* WM_API_H */
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 73f1fe8cbd3..0447524255f 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -28,6 +28,10 @@
#ifndef WM_TYPES_H
#define WM_TYPES_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bContext;
struct wmEvent;
struct wmWindowManager;
@@ -511,5 +515,9 @@ typedef struct RecentFile {
} RecentFile;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* WM_TYPES_H */