* added armature/skinned mesh export
* meshes are now exported without modifiers applied (for skinning to work), this should become a configurable option later * had to edit OpenCollada code to make armature/skinning import work correctly * code layout improvements
This commit is contained in:
@@ -27,6 +27,7 @@ extern "C"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_action.h" // pose functions
|
||||
#include "BKE_armature.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_string.h"
|
||||
@@ -64,6 +65,7 @@ extern "C"
|
||||
#include "COLLADASWCameraOptic.h"
|
||||
#include "COLLADASWConstants.h"
|
||||
#include "COLLADASWLibraryControllers.h"
|
||||
#include "COLLADASWInstanceController.h"
|
||||
#include "COLLADASWBaseInputElement.h"
|
||||
|
||||
#include "collada_internal.h"
|
||||
@@ -114,11 +116,27 @@ char *CustomData_get_active_layer_name(const CustomData *data, int type)
|
||||
return data->layers[layer_index].name;
|
||||
}
|
||||
|
||||
std::string id_name(void *id)
|
||||
static std::string id_name(void *id)
|
||||
{
|
||||
return ((ID*)id)->name + 2;
|
||||
}
|
||||
|
||||
static std::string get_geometry_id(Object *ob)
|
||||
{
|
||||
return id_name(ob) + "-mesh";
|
||||
}
|
||||
|
||||
static void replace_chars(char *str, char chars[], char with)
|
||||
{
|
||||
char *ch, *p;
|
||||
|
||||
for (ch = chars; *ch; ch++) {
|
||||
while ((p = strchr(str, *ch))) {
|
||||
*p = with;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Utilities to avoid code duplication.
|
||||
Definition can take some time to understand, but they should be useful.
|
||||
@@ -251,32 +269,33 @@ public:
|
||||
void operator()(Object *ob)
|
||||
{
|
||||
// XXX don't use DerivedMesh, Mesh instead?
|
||||
|
||||
|
||||
#if 0
|
||||
DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
|
||||
#endif
|
||||
Mesh *me = (Mesh*)ob->data;
|
||||
std::string geom_name(id_name(ob));
|
||||
std::string geom_id = get_geometry_id(ob);
|
||||
|
||||
// openMesh(geoId, geoName, meshId)
|
||||
openMesh(geom_name, "", "");
|
||||
openMesh(geom_id, "", "");
|
||||
|
||||
// writes <source> for vertex coords
|
||||
createVertsSource(geom_name, dm);
|
||||
createVertsSource(geom_id, me);
|
||||
|
||||
// writes <source> for normal coords
|
||||
createNormalsSource(geom_name, dm);
|
||||
createNormalsSource(geom_id, me);
|
||||
|
||||
int has_uvs = CustomData_has_layer(&me->fdata, CD_MTFACE);
|
||||
|
||||
// writes <source> for uv coords if mesh has uv coords
|
||||
if (has_uvs) {
|
||||
createTexcoordsSource(geom_name, dm, (Mesh*)ob->data);
|
||||
createTexcoordsSource(geom_id, (Mesh*)ob->data);
|
||||
}
|
||||
// <vertices>
|
||||
COLLADASW::Vertices verts(mSW);
|
||||
verts.setId(getIdBySemantics(geom_name, COLLADASW::VERTEX));
|
||||
verts.setId(getIdBySemantics(geom_id, COLLADASW::VERTEX));
|
||||
COLLADASW::InputList &input_list = verts.getInputList();
|
||||
COLLADASW::Input input(COLLADASW::POSITION,
|
||||
getUrlBySemantics(geom_name, COLLADASW::POSITION));
|
||||
COLLADASW::Input input(COLLADASW::POSITION, getUrlBySemantics(geom_id, COLLADASW::POSITION));
|
||||
input_list.push_back(input);
|
||||
verts.add();
|
||||
|
||||
@@ -285,18 +304,19 @@ public:
|
||||
for(int a = 0; a < ob->totcol; a++) {
|
||||
// account for NULL materials, this should not normally happen?
|
||||
Material *ma = give_current_material(ob, a + 1);
|
||||
createPolylist(ma != NULL, a, has_uvs, ob, dm, geom_name);
|
||||
createPolylist(ma != NULL, a, has_uvs, ob, geom_id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
createPolylist(false, 0, has_uvs, ob, dm, geom_name);
|
||||
createPolylist(false, 0, has_uvs, ob, geom_id);
|
||||
}
|
||||
|
||||
closeMesh();
|
||||
closeGeometry();
|
||||
|
||||
#if 0
|
||||
dm->release(dm);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// powerful because it handles both cases when there is material and when there's not
|
||||
@@ -304,12 +324,15 @@ public:
|
||||
int material_index,
|
||||
bool has_uvs,
|
||||
Object *ob,
|
||||
DerivedMesh *dm,
|
||||
std::string& geom_name)
|
||||
std::string& geom_id)
|
||||
{
|
||||
#if 0
|
||||
MFace *mfaces = dm->getFaceArray(dm);
|
||||
int totfaces = dm->getNumFaces(dm);
|
||||
#endif
|
||||
Mesh *me = (Mesh*)ob->data;
|
||||
MFace *mfaces = me->mface;
|
||||
int totfaces = me->totface;
|
||||
|
||||
// <vcount>
|
||||
int i;
|
||||
@@ -350,11 +373,11 @@ public:
|
||||
|
||||
// creates <input> in <polylist> for vertices
|
||||
COLLADASW::Input input1(COLLADASW::VERTEX, getUrlBySemantics
|
||||
(geom_name, COLLADASW::VERTEX), 0);
|
||||
(geom_id, COLLADASW::VERTEX), 0);
|
||||
|
||||
// creates <input> in <polylist> for normals
|
||||
COLLADASW::Input input2(COLLADASW::NORMAL, getUrlBySemantics
|
||||
(geom_name, COLLADASW::NORMAL), 0);
|
||||
(geom_id, COLLADASW::NORMAL), 0);
|
||||
|
||||
til.push_back(input1);
|
||||
til.push_back(input2);
|
||||
@@ -365,7 +388,7 @@ public:
|
||||
for (i = 0; i < num_layers; i++) {
|
||||
char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
|
||||
COLLADASW::Input input3(COLLADASW::TEXCOORD,
|
||||
makeUrl(makeTexcoordSourceId(geom_name, i)),
|
||||
makeUrl(makeTexcoordSourceId(geom_id, i)),
|
||||
1, // offset always 1, this is only until we have optimized UV sets
|
||||
i // set number equals UV layer index
|
||||
);
|
||||
@@ -403,15 +426,18 @@ public:
|
||||
}
|
||||
|
||||
// creates <source> for positions
|
||||
void createVertsSource(std::string geom_name, DerivedMesh *dm)
|
||||
void createVertsSource(std::string geom_id, Mesh *me)
|
||||
{
|
||||
#if 0
|
||||
int totverts = dm->getNumVerts(dm);
|
||||
MVert *verts = dm->getVertArray(dm);
|
||||
|
||||
#endif
|
||||
int totverts = me->totvert;
|
||||
MVert *verts = me->mvert;
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(getIdBySemantics(geom_name, COLLADASW::POSITION));
|
||||
source.setArrayId(getIdBySemantics(geom_name, COLLADASW::POSITION) +
|
||||
source.setId(getIdBySemantics(geom_id, COLLADASW::POSITION));
|
||||
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::POSITION) +
|
||||
ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(totverts);
|
||||
source.setAccessorStride(3);
|
||||
@@ -425,27 +451,30 @@ public:
|
||||
//appends data to <float_array>
|
||||
int i = 0;
|
||||
for (i = 0; i < totverts; i++) {
|
||||
source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
|
||||
|
||||
source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
|
||||
}
|
||||
|
||||
std::string makeTexcoordSourceId(std::string& geom_name, int layer_index)
|
||||
std::string makeTexcoordSourceId(std::string& geom_id, int layer_index)
|
||||
{
|
||||
char suffix[20];
|
||||
sprintf(suffix, "-%d", layer_index);
|
||||
return getIdBySemantics(geom_name, COLLADASW::TEXCOORD) + suffix;
|
||||
return getIdBySemantics(geom_id, COLLADASW::TEXCOORD) + suffix;
|
||||
}
|
||||
|
||||
//creates <source> for texcoords
|
||||
void createTexcoordsSource(std::string geom_name, DerivedMesh *dm, Mesh *me)
|
||||
void createTexcoordsSource(std::string geom_id, Mesh *me)
|
||||
{
|
||||
|
||||
#if 0
|
||||
int totfaces = dm->getNumFaces(dm);
|
||||
MFace *mfaces = dm->getFaceArray(dm);
|
||||
#endif
|
||||
int totfaces = me->totface;
|
||||
MFace *mfaces = me->mface;
|
||||
|
||||
int totuv = 0;
|
||||
int i;
|
||||
|
||||
@@ -469,7 +498,7 @@ public:
|
||||
char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
std::string layer_id = makeTexcoordSourceId(geom_name, a);
|
||||
std::string layer_id = makeTexcoordSourceId(geom_id, a);
|
||||
source.setId(layer_id);
|
||||
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
|
||||
|
||||
@@ -496,14 +525,19 @@ public:
|
||||
|
||||
|
||||
//creates <source> for normals
|
||||
void createNormalsSource(std::string geom_name, DerivedMesh *dm)
|
||||
void createNormalsSource(std::string geom_id, Mesh *me)
|
||||
{
|
||||
#if 0
|
||||
int totverts = dm->getNumVerts(dm);
|
||||
MVert *verts = dm->getVertArray(dm);
|
||||
|
||||
#endif
|
||||
|
||||
int totverts = me->totvert;
|
||||
MVert *verts = me->mvert;
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(getIdBySemantics(geom_name, COLLADASW::NORMAL));
|
||||
source.setArrayId(getIdBySemantics(geom_name, COLLADASW::NORMAL) +
|
||||
source.setId(getIdBySemantics(geom_id, COLLADASW::NORMAL));
|
||||
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::NORMAL) +
|
||||
ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(totverts);
|
||||
source.setAccessorStride(3);
|
||||
@@ -526,14 +560,14 @@ public:
|
||||
source.finish();
|
||||
}
|
||||
|
||||
std::string getIdBySemantics(std::string geom_name, COLLADASW::Semantics type, std::string other_suffix = "") {
|
||||
return geom_name + getSuffixBySemantic(type) + other_suffix;
|
||||
std::string getIdBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") {
|
||||
return geom_id + getSuffixBySemantic(type) + other_suffix;
|
||||
}
|
||||
|
||||
|
||||
COLLADASW::URI getUrlBySemantics(std::string geom_name, COLLADASW::Semantics type, std::string other_suffix = "") {
|
||||
COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") {
|
||||
|
||||
std::string id(getIdBySemantics(geom_name, type, other_suffix));
|
||||
std::string id(getIdBySemantics(geom_id, type, other_suffix));
|
||||
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
|
||||
|
||||
}
|
||||
@@ -559,14 +593,120 @@ public:
|
||||
}*/
|
||||
};
|
||||
|
||||
// XXX exporter assumes armatures are not shared between meshes.
|
||||
class ArmatureExporter: COLLADASW::LibraryControllers
|
||||
class TransformWriter : protected TransformBase
|
||||
{
|
||||
protected:
|
||||
void add_node_transform(COLLADASW::Node& node, float mat[][4])
|
||||
{
|
||||
float loc[3], rot[3], size[3];
|
||||
|
||||
TransformBase::decompose(mat, loc, rot, size);
|
||||
|
||||
/*
|
||||
// this code used to create a single <rotate> representing object rotation
|
||||
float quat[4];
|
||||
float axis[3];
|
||||
float angle;
|
||||
double angle_deg;
|
||||
EulToQuat(rot, quat);
|
||||
NormalQuat(quat);
|
||||
QuatToAxisAngle(quat, axis, &angle);
|
||||
angle_deg = angle * 180.0f / M_PI;
|
||||
node.addRotate(axis[0], axis[1], axis[2], angle_deg);
|
||||
*/
|
||||
node.addTranslate("location", loc[0], loc[1], loc[2]);
|
||||
|
||||
node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2]));
|
||||
node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1]));
|
||||
node.addRotateX("rotationX", COLLADABU::Math::Utils::radToDegF(rot[0]));
|
||||
|
||||
node.addScale("scale", size[0], size[1], size[2]);
|
||||
}
|
||||
};
|
||||
|
||||
class InstanceWriter
|
||||
{
|
||||
protected:
|
||||
void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob)
|
||||
{
|
||||
for(int a = 0; a < ob->totcol; a++) {
|
||||
Material *ma = give_current_material(ob, a+1);
|
||||
|
||||
COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
|
||||
|
||||
if (ma) {
|
||||
std::string matid(id_name(ma));
|
||||
COLLADASW::InstanceMaterial im(matid, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
|
||||
|
||||
// create <bind_vertex_input> for each uv layer
|
||||
Mesh *me = (Mesh*)ob->data;
|
||||
int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
|
||||
|
||||
for (int b = 0; b < totlayer; b++) {
|
||||
char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
|
||||
im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", b));
|
||||
}
|
||||
|
||||
iml.push_back(im);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// XXX exporter writes wrong data for shared armatures. A separate
|
||||
// controller should be written for each armature-mesh binding how do
|
||||
// we make controller ids then?
|
||||
class ArmatureExporter: public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
|
||||
{
|
||||
private:
|
||||
Scene *scene;
|
||||
|
||||
public:
|
||||
ArmatureExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryControllers(sw) {}
|
||||
|
||||
void export_armatures(Scene *sce)
|
||||
// write bone nodes
|
||||
void add_armature_bones(Object *ob_arm, Scene *sce)
|
||||
{
|
||||
// write bone nodes
|
||||
bArmature *arm = (bArmature*)ob_arm->data;
|
||||
for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
|
||||
// start from root bones
|
||||
if (!bone->parent)
|
||||
add_bone_node(bone, ob_arm);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_skinned_mesh(Object *ob)
|
||||
{
|
||||
return get_assigned_armature(ob) != NULL;
|
||||
}
|
||||
|
||||
void add_instance_controller(Object *ob)
|
||||
{
|
||||
Object *ob_arm = get_assigned_armature(ob);
|
||||
bArmature *arm = (bArmature*)ob_arm->data;
|
||||
|
||||
const std::string& controller_id = get_controller_id(ob_arm);
|
||||
|
||||
COLLADASW::InstanceController ins(mSW);
|
||||
ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id));
|
||||
|
||||
// write root bone URLs
|
||||
Bone *bone;
|
||||
for (bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
|
||||
if (!bone->parent)
|
||||
ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
|
||||
}
|
||||
|
||||
InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob);
|
||||
|
||||
ins.add();
|
||||
}
|
||||
|
||||
void export_controllers(Scene *sce)
|
||||
{
|
||||
scene = sce;
|
||||
|
||||
openLibrary();
|
||||
|
||||
forEachMeshObjectInScene(sce, *this);
|
||||
@@ -575,8 +715,51 @@ public:
|
||||
}
|
||||
|
||||
void operator()(Object *ob)
|
||||
{
|
||||
Object *ob_arm = get_assigned_armature(ob);
|
||||
|
||||
if (ob_arm /*&& !already_written(ob_arm)*/)
|
||||
export_controller(ob, ob_arm);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
UnitConverter converter;
|
||||
|
||||
#if 0
|
||||
std::vector<Object*> written_armatures;
|
||||
|
||||
bool already_written(Object *ob_arm)
|
||||
{
|
||||
return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) != written_armatures.end();
|
||||
}
|
||||
|
||||
void wrote(Object *ob_arm)
|
||||
{
|
||||
written_armatures.push_back(ob_arm);
|
||||
}
|
||||
|
||||
void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce)
|
||||
{
|
||||
objects.clear();
|
||||
|
||||
Base *base= (Base*) sce->base.first;
|
||||
while(base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
|
||||
objects.push_back(ob);
|
||||
}
|
||||
|
||||
base= base->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Object *get_assigned_armature(Object *ob)
|
||||
{
|
||||
Object *ob_arm = NULL;
|
||||
|
||||
if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
|
||||
ob_arm = ob->parent;
|
||||
}
|
||||
@@ -591,17 +774,82 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (ob_arm)
|
||||
export_armature(ob, ob_arm);
|
||||
return ob_arm;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string get_joint_id(Bone *bone, Object *ob_arm)
|
||||
{
|
||||
return id_name(ob_arm) + "_" + bone->name;
|
||||
}
|
||||
|
||||
UnitConverter converter;
|
||||
std::string get_joint_sid(Bone *bone)
|
||||
{
|
||||
char name[100];
|
||||
BLI_strncpy(name, bone->name, sizeof(name));
|
||||
|
||||
// these chars have special meaning in SID
|
||||
replace_chars(name, ".()", '_');
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// parent_mat is armature-space
|
||||
void add_bone_node(Bone *bone, Object *ob_arm)
|
||||
{
|
||||
std::string node_id = get_joint_id(bone, ob_arm);
|
||||
std::string node_name = std::string(bone->name);
|
||||
std::string node_sid = get_joint_sid(bone);
|
||||
|
||||
COLLADASW::Node node(mSW);
|
||||
|
||||
node.setType(COLLADASW::Node::JOINT);
|
||||
node.setNodeId(node_id);
|
||||
node.setNodeName(node_name);
|
||||
node.setNodeSid(node_sid);
|
||||
|
||||
node.start();
|
||||
|
||||
add_bone_transform(ob_arm, bone, node);
|
||||
|
||||
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
|
||||
add_bone_node(child, ob_arm);
|
||||
}
|
||||
|
||||
node.end();
|
||||
}
|
||||
|
||||
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
|
||||
{
|
||||
bPose *pose = ob_arm->pose;
|
||||
|
||||
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
|
||||
|
||||
float mat[4][4];
|
||||
|
||||
if (bone->parent) {
|
||||
// get bone-space matrix from armature-space
|
||||
bPoseChannel *parchan = get_pose_channel(ob_arm->pose, bone->parent->name);
|
||||
|
||||
float invpar[4][4];
|
||||
Mat4Invert(invpar, parchan->pose_mat);
|
||||
Mat4MulMat4(mat, pchan->pose_mat, invpar);
|
||||
}
|
||||
else {
|
||||
// get world-space from armature-space
|
||||
Mat4MulMat4(mat, pchan->pose_mat, ob_arm->obmat);
|
||||
}
|
||||
|
||||
TransformWriter::add_node_transform(node, mat);
|
||||
}
|
||||
|
||||
std::string get_controller_id(Object *ob_arm)
|
||||
{
|
||||
return id_name(ob_arm) + SKIN_CONTROLLER_ID_SUFFIX;
|
||||
}
|
||||
|
||||
// ob should be of type OB_MESH
|
||||
// both args are required
|
||||
void export_armature(Object* ob, Object *ob_arm)
|
||||
void export_controller(Object* ob, Object *ob_arm)
|
||||
{
|
||||
// joint names
|
||||
// joint inverse bind matrices
|
||||
@@ -629,20 +877,20 @@ private:
|
||||
Mesh *me = (Mesh*)ob->data;
|
||||
if (!me->dvert) return;
|
||||
|
||||
std::string controller_name(ob_arm->id.name);
|
||||
std::string controller_id = controller_name + SKIN_CONTROLLER_ID_SUFFIX;
|
||||
std::string controller_name = id_name(ob_arm);
|
||||
std::string controller_id = get_controller_id(ob_arm);
|
||||
|
||||
openSkin(controller_id, controller_name, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, ob->id.name));
|
||||
openSkin(controller_id, controller_name,
|
||||
COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
|
||||
|
||||
add_bind_shape_mat(ob);
|
||||
|
||||
std::string joints_source_id = add_joints_source(&ob->defbase, controller_id);
|
||||
std::string inv_bind_mat_source_id =
|
||||
add_inv_bind_mats_source((bArmature*)ob_arm->data, &ob->defbase, controller_id);
|
||||
std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id);
|
||||
std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id);
|
||||
std::string weights_source_id = add_weights_source(me, controller_id);
|
||||
|
||||
add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
|
||||
add_vertex_weights_element(weights_source_id, joints_source_id, me);
|
||||
add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase);
|
||||
|
||||
closeSkin();
|
||||
closeController();
|
||||
@@ -664,25 +912,28 @@ private:
|
||||
|
||||
void add_bind_shape_mat(Object *ob)
|
||||
{
|
||||
float ob_bind_mat[4][4];
|
||||
double dae_mat[4][4];
|
||||
double bind_mat[4][4];
|
||||
|
||||
// TODO: get matrix from ob
|
||||
Mat4One(ob_bind_mat);
|
||||
converter.mat4_to_dae_double(bind_mat, ob->obmat);
|
||||
|
||||
converter.mat4_to_dae(dae_mat, ob_bind_mat);
|
||||
|
||||
addBindShapeTransform(dae_mat);
|
||||
addBindShapeTransform(bind_mat);
|
||||
}
|
||||
|
||||
std::string add_joints_source(ListBase *defbase, const std::string& controller_id)
|
||||
std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
|
||||
{
|
||||
std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
|
||||
|
||||
int totjoint = 0;
|
||||
bDeformGroup *def;
|
||||
for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
|
||||
if (is_bone_defgroup(ob_arm, def))
|
||||
totjoint++;
|
||||
}
|
||||
|
||||
COLLADASW::NameSource source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(BLI_countlist(defbase));
|
||||
source.setAccessorCount(totjoint);
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
@@ -690,10 +941,10 @@ private:
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
bDeformGroup *def;
|
||||
|
||||
for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
|
||||
source.appendValues(def->name);
|
||||
Bone *bone = get_bone_from_defgroup(ob_arm, def);
|
||||
if (bone)
|
||||
source.appendValues(get_joint_sid(bone));
|
||||
}
|
||||
|
||||
source.finish();
|
||||
@@ -701,7 +952,7 @@ private:
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string add_inv_bind_mats_source(bArmature *arm, ListBase *defbase, const std::string& controller_id)
|
||||
std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
|
||||
{
|
||||
std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
|
||||
|
||||
@@ -717,22 +968,40 @@ private:
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
bDeformGroup *def;
|
||||
bPose *pose = ob_arm->pose;
|
||||
bArmature *arm = (bArmature*)ob_arm->data;
|
||||
|
||||
/*
|
||||
Bone *get_named_bone (struct bArmature *arm, const char *name);
|
||||
bPoseChannel *get_pose_channel(const struct bPose *pose, const char *name);
|
||||
*/
|
||||
int flag = arm->flag;
|
||||
|
||||
float inv_bind_mat[4][4];
|
||||
Mat4One(inv_bind_mat);
|
||||
// put armature in rest position
|
||||
if (!(arm->flag & ARM_RESTPOS)) {
|
||||
arm->flag |= ARM_RESTPOS;
|
||||
where_is_pose(scene, ob_arm);
|
||||
}
|
||||
|
||||
float dae_mat[4][4];
|
||||
converter.mat4_to_dae(dae_mat, inv_bind_mat);
|
||||
for (bDeformGroup *def = (bDeformGroup*)defbase->first; def; def = def->next) {
|
||||
if (is_bone_defgroup(ob_arm, def)) {
|
||||
|
||||
// TODO: write inverse bind matrices for each bone (name taken from defbase)
|
||||
for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
|
||||
source.appendValues(dae_mat);
|
||||
bPoseChannel *pchan = get_pose_channel(pose, def->name);
|
||||
|
||||
float mat[4][4];
|
||||
float world[4][4];
|
||||
float inv_bind_mat[4][4];
|
||||
|
||||
// make world-space matrix, pose_mat is armature-space
|
||||
Mat4MulMat4(world, pchan->pose_mat, ob_arm->obmat);
|
||||
|
||||
Mat4Invert(mat, world);
|
||||
converter.mat4_to_dae(inv_bind_mat, mat);
|
||||
|
||||
source.appendValues(inv_bind_mat);
|
||||
}
|
||||
}
|
||||
|
||||
// back from rest positon
|
||||
if (!(flag & ARM_RESTPOS)) {
|
||||
arm->flag = flag;
|
||||
where_is_pose(scene, ob_arm);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
@@ -740,14 +1009,32 @@ private:
|
||||
return source_id;
|
||||
}
|
||||
|
||||
Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def)
|
||||
{
|
||||
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, def->name);
|
||||
return pchan ? pchan->bone : NULL;
|
||||
}
|
||||
|
||||
bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def)
|
||||
{
|
||||
return get_bone_from_defgroup(ob_arm, def) != NULL;
|
||||
}
|
||||
|
||||
std::string add_weights_source(Mesh *me, const std::string& controller_id)
|
||||
{
|
||||
std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
|
||||
|
||||
int i;
|
||||
int totweight = 0;
|
||||
|
||||
for (i = 0; i < me->totvert; i++) {
|
||||
totweight += me->dvert[i].totweight;
|
||||
}
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(me->totvert);
|
||||
source.setAccessorCount(totweight);
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
@@ -757,7 +1044,7 @@ private:
|
||||
|
||||
// NOTE: COLLADA spec says weights should be normalized
|
||||
|
||||
for (int i = 0; i < me->totvert; i++) {
|
||||
for (i = 0; i < me->totvert; i++) {
|
||||
MDeformVert *vert = &me->dvert[i];
|
||||
for (int j = 0; j < vert->totweight; j++) {
|
||||
source.appendValues(vert->dw[j].weight);
|
||||
@@ -769,7 +1056,8 @@ private:
|
||||
return source_id;
|
||||
}
|
||||
|
||||
void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me)
|
||||
void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
|
||||
Object *ob_arm, ListBase *defbase)
|
||||
{
|
||||
COLLADASW::VertexWeightsElement weights(mSW);
|
||||
COLLADASW::InputList &input = weights.getInputList();
|
||||
@@ -792,30 +1080,39 @@ private:
|
||||
weights.prepareToAppendVCountValues();
|
||||
weights.appendVertexCount(vcount);
|
||||
|
||||
std::vector<unsigned long> indices;
|
||||
// def group index -> joint index
|
||||
std::map<int, int> joint_index_by_def_index;
|
||||
bDeformGroup *def;
|
||||
int j;
|
||||
for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
|
||||
if (is_bone_defgroup(ob_arm, def))
|
||||
joint_index_by_def_index[i] = j++;
|
||||
else
|
||||
joint_index_by_def_index[i] = -1;
|
||||
}
|
||||
|
||||
weights.CloseVCountAndOpenVElement();
|
||||
|
||||
// write deformer index - weight index pairs
|
||||
int weight_index = 0;
|
||||
for (i = 0; i < me->totvert; i++) {
|
||||
MDeformVert *dvert = &me->dvert[i];
|
||||
|
||||
for (int j = 0; j < dvert->totweight; j++) {
|
||||
indices.push_back(dvert->dw[j].def_nr);
|
||||
indices.push_back(weight_index++);
|
||||
weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]);
|
||||
weights.appendValues(weight_index++);
|
||||
}
|
||||
}
|
||||
|
||||
weights.CloseVCountAndOpenVElement();
|
||||
weights.appendValues(indices);
|
||||
|
||||
weights.finish();
|
||||
}
|
||||
};
|
||||
|
||||
class SceneExporter: COLLADASW::LibraryVisualScenes
|
||||
class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
|
||||
{
|
||||
ArmatureExporter *arm_exporter;
|
||||
public:
|
||||
SceneExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryVisualScenes(sw) {}
|
||||
SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw),
|
||||
arm_exporter(arm) {}
|
||||
|
||||
void exportScene(Scene *sce) {
|
||||
// <library_visual_scenes> <visual_scene>
|
||||
@@ -833,66 +1130,75 @@ public:
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void exportHierarchy(Scene *sce)
|
||||
{
|
||||
Base *base= (Base*) sce->base.first;
|
||||
while(base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (!ob->parent) {
|
||||
switch(ob->type) {
|
||||
case OB_MESH:
|
||||
case OB_CAMERA:
|
||||
case OB_LAMP:
|
||||
case OB_EMPTY:
|
||||
case OB_ARMATURE:
|
||||
// write nodes....
|
||||
writeNodes(ob, sce);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
base= base->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// called for each object
|
||||
//void operator()(Object *ob) {
|
||||
void writeNodes(Object *ob, Scene *sce) {
|
||||
|
||||
void writeNodes(Object *ob, Scene *sce)
|
||||
{
|
||||
COLLADASW::Node node(mSW);
|
||||
node.setNodeId(ob->id.name);
|
||||
node.setNodeId(id_name(ob));
|
||||
node.setType(COLLADASW::Node::NODE);
|
||||
|
||||
std::string ob_name(id_name(ob));
|
||||
|
||||
node.start();
|
||||
node.addTranslate("location", ob->loc[0], ob->loc[1], ob->loc[2]);
|
||||
|
||||
bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
|
||||
|
||||
float mat[4][4];
|
||||
|
||||
// this code used to create a single <rotate> representing object rotation
|
||||
// float quat[4];
|
||||
// float axis[3];
|
||||
// float angle;
|
||||
// double angle_deg;
|
||||
// EulToQuat(ob->rot, quat);
|
||||
// NormalQuat(quat);
|
||||
// QuatToAxisAngle(quat, axis, &angle);
|
||||
// angle_deg = angle * 180.0f / M_PI;
|
||||
// node.addRotate(axis[0], axis[1], axis[2], angle_deg);
|
||||
if (ob->type == OB_MESH && is_skinned_mesh)
|
||||
// for skinned mesh we write obmat in <bind_shape_matrix>
|
||||
Mat4One(mat);
|
||||
else
|
||||
Mat4CpyMat4(mat, ob->obmat);
|
||||
|
||||
float *rot = ob->rot;
|
||||
node.addRotateX("rotationX", COLLADABU::Math::Utils::radToDegF(rot[0]));
|
||||
node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1]));
|
||||
node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2]));
|
||||
|
||||
node.addScale("scale", ob->size[0], ob->size[1], ob->size[2]);
|
||||
TransformWriter::add_node_transform(node, mat);
|
||||
|
||||
// <instance_geometry>
|
||||
if (ob->type == OB_MESH) {
|
||||
COLLADASW::InstanceGeometry instGeom(mSW);
|
||||
instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, ob_name));
|
||||
|
||||
for(int a = 0; a < ob->totcol; a++) {
|
||||
Material *ma = give_current_material(ob, a+1);
|
||||
|
||||
COLLADASW::BindMaterial& bm = instGeom.getBindMaterial();
|
||||
COLLADASW::InstanceMaterialList& iml = bm.getInstanceMaterialList();
|
||||
|
||||
if (ma) {
|
||||
std::string matid(id_name(ma));
|
||||
COLLADASW::InstanceMaterial im(matid, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
|
||||
|
||||
// create <bind_vertex_input> for each uv layer
|
||||
Mesh *me = (Mesh*)ob->data;
|
||||
int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
|
||||
|
||||
for (int b = 0; b < totlayer; b++) {
|
||||
char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
|
||||
im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", b));
|
||||
}
|
||||
|
||||
iml.push_back(im);
|
||||
}
|
||||
if (is_skinned_mesh) {
|
||||
arm_exporter->add_instance_controller(ob);
|
||||
}
|
||||
else {
|
||||
COLLADASW::InstanceGeometry instGeom(mSW);
|
||||
instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
|
||||
|
||||
InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
|
||||
|
||||
instGeom.add();
|
||||
instGeom.add();
|
||||
}
|
||||
}
|
||||
|
||||
// <instance_controller>
|
||||
else if (ob->type == OB_ARMATURE) {
|
||||
arm_exporter->add_armature_bones(ob, sce);
|
||||
|
||||
// XXX this looks unstable...
|
||||
node.end();
|
||||
}
|
||||
|
||||
// <instance_camera>
|
||||
@@ -906,41 +1212,36 @@ public:
|
||||
COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, ob_name));
|
||||
instLa.add();
|
||||
}
|
||||
|
||||
// empty object
|
||||
else if (ob->type == OB_EMPTY) {
|
||||
}
|
||||
|
||||
// write node for child object
|
||||
|
||||
// write nodes for child objects
|
||||
Base *b = (Base*) sce->base.first;
|
||||
while(b) {
|
||||
// cob - child object
|
||||
Object *cob = b->object;
|
||||
|
||||
if ((cob->type == OB_MESH || cob->type == OB_CAMERA || cob->type == OB_LAMP || cob->type == OB_EMPTY) && cob->parent == ob) {
|
||||
// write node...
|
||||
writeNodes(cob, sce);
|
||||
|
||||
if (cob->parent == ob) {
|
||||
switch(cob->type) {
|
||||
case OB_MESH:
|
||||
case OB_CAMERA:
|
||||
case OB_LAMP:
|
||||
case OB_EMPTY:
|
||||
case OB_ARMATURE:
|
||||
// write node...
|
||||
writeNodes(cob, sce);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
b = b->next;
|
||||
}
|
||||
|
||||
node.end();
|
||||
}
|
||||
|
||||
void exportHierarchy(Scene *sce)
|
||||
{
|
||||
Base *base= (Base*) sce->base.first;
|
||||
while(base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if ((ob->type == OB_MESH || ob->type == OB_CAMERA || ob->type == OB_LAMP || ob->type == OB_EMPTY) && !ob->parent) {
|
||||
// write nodes....
|
||||
writeNodes(ob, sce);
|
||||
|
||||
}
|
||||
base= base->next;
|
||||
}
|
||||
if (ob->type != OB_ARMATURE)
|
||||
node.end();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class ImagesExporter: COLLADASW::LibraryImages
|
||||
@@ -1349,7 +1650,7 @@ public:
|
||||
}
|
||||
|
||||
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
|
||||
Sampler::Semantic semantic, bool rotation, char *axis) {
|
||||
Sampler::Semantic semantic, bool rotation, const char *axis) {
|
||||
switch(semantic) {
|
||||
case Sampler::INPUT:
|
||||
param.push_back("TIME");
|
||||
@@ -1394,7 +1695,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::string create_source(Sampler::Semantic semantic, FCurve *fcu, std::string& anim_id, char *axis_name)
|
||||
std::string create_source(Sampler::Semantic semantic, FCurve *fcu, std::string& anim_id, const char *axis_name)
|
||||
{
|
||||
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
||||
|
||||
@@ -1425,7 +1726,7 @@ public:
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string create_interpolation_source(FCurve *fcu, std::string& anim_id, char *axis_name)
|
||||
std::string create_interpolation_source(FCurve *fcu, std::string& anim_id, const char *axis_name)
|
||||
{
|
||||
std::string source_id = anim_id + get_semantic_suffix(Sampler::INTERPOLATION);
|
||||
|
||||
@@ -1452,7 +1753,7 @@ public:
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string get_transform_sid(char *rna_path, char *axis_name)
|
||||
std::string get_transform_sid(char *rna_path, const char *axis_name)
|
||||
{
|
||||
if (!strcmp(rna_path, "rotation"))
|
||||
return std::string(rna_path) + axis_name;
|
||||
@@ -1462,8 +1763,8 @@ public:
|
||||
|
||||
void add_animation(FCurve *fcu, const char *ob_name)
|
||||
{
|
||||
static char *axis_names[] = {"X", "Y", "Z"};
|
||||
char *axis_name = NULL;
|
||||
const char *axis_names[] = {"X", "Y", "Z"};
|
||||
const char *axis_name = NULL;
|
||||
char c_anim_id[100]; // careful!
|
||||
|
||||
if (fcu->array_index < 3)
|
||||
@@ -1537,7 +1838,7 @@ void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
|
||||
// <asset>
|
||||
COLLADASW::Asset asset(&sw);
|
||||
// XXX ask blender devs about this?
|
||||
asset.setUnit("meter", 1.0);
|
||||
asset.setUnit("decimetre", 0.1);
|
||||
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
|
||||
asset.add();
|
||||
|
||||
@@ -1570,10 +1871,11 @@ void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
|
||||
ae.exportAnimations(sce);
|
||||
|
||||
// <library_controllers>
|
||||
ArmatureExporter(&sw).export_armatures(sce);
|
||||
ArmatureExporter arm_exporter(&sw);
|
||||
arm_exporter.export_controllers(sce);
|
||||
|
||||
// <library_visual_scenes>
|
||||
SceneExporter se(&sw);
|
||||
SceneExporter se(&sw, &arm_exporter);
|
||||
se.exportScene(sce);
|
||||
|
||||
// <scene>
|
||||
|
||||
@@ -139,8 +139,19 @@ const char *get_dae_name(T *node)
|
||||
return name.size() ? name.c_str() : node->getOriginalId().c_str();
|
||||
}
|
||||
|
||||
// use this for retrieving bone names, since these must be unique
|
||||
template<class T>
|
||||
const char *get_joint_name(T *node)
|
||||
{
|
||||
const std::string& id = node->getOriginalId();
|
||||
return id.size() ? id.c_str() : node->getName().c_str();
|
||||
}
|
||||
|
||||
float get_float_value(const COLLADAFW::FloatOrDoubleArray& array, int index)
|
||||
{
|
||||
if (index >= array.getValuesCount())
|
||||
return 0.0f;
|
||||
|
||||
if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
|
||||
return array.getFloatValues()->getData()[index];
|
||||
else
|
||||
@@ -156,7 +167,95 @@ public:
|
||||
virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0;
|
||||
};
|
||||
|
||||
class ArmatureImporter
|
||||
class TransformReader : protected 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];
|
||||
|
||||
Mat4One(mat);
|
||||
|
||||
for (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:
|
||||
{
|
||||
COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm;
|
||||
COLLADABU::Math::Vector3& t = tra->getTranslation();
|
||||
|
||||
Mat4One(cur);
|
||||
cur[3][0] = (float)t[0];
|
||||
cur[3][1] = (float)t[1];
|
||||
cur[3][2] = (float)t[2];
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::ROTATE:
|
||||
{
|
||||
COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm;
|
||||
COLLADABU::Math::Vector3& raxis = ro->getRotationAxis();
|
||||
float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f);
|
||||
float axis[] = {raxis[0], raxis[1], raxis[2]};
|
||||
float quat[4];
|
||||
float rot_copy[3][3];
|
||||
float mat[3][3];
|
||||
AxisAngleToQuat(quat, axis, angle);
|
||||
|
||||
QuatToMat4(quat, cur);
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::SCALE:
|
||||
{
|
||||
COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale();
|
||||
float size[3] = {(float)s[0], (float)s[1], (float)s[2]};
|
||||
SizeToMat4(size, cur);
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::MATRIX:
|
||||
{
|
||||
unit_converter->mat4_from_dae(cur, ((COLLADAFW::Matrix*)tm)->getMatrix());
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::LOOKAT:
|
||||
case COLLADAFW::Transformation::SKEW:
|
||||
fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
Mat4CpyMat4(copy, mat);
|
||||
Mat4MulMat4(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ArmatureImporter : private TransformReader
|
||||
{
|
||||
private:
|
||||
Scene *scene;
|
||||
@@ -210,7 +309,7 @@ private:
|
||||
// data from COLLADAFW::SkinControllerData, each array should be freed
|
||||
COLLADAFW::UIntValuesArray joints_per_vertex;
|
||||
COLLADAFW::UIntValuesArray weight_indices;
|
||||
COLLADAFW::UIntValuesArray joint_indices;
|
||||
COLLADAFW::IntValuesArray joint_indices;
|
||||
// COLLADAFW::FloatOrDoubleArray weights;
|
||||
std::vector<float> weights;
|
||||
|
||||
@@ -220,6 +319,7 @@ private:
|
||||
|
||||
Object *ob_arm;
|
||||
COLLADAFW::UniqueId controller_uid;
|
||||
|
||||
public:
|
||||
|
||||
SkinInfo() {}
|
||||
@@ -232,23 +332,30 @@ private:
|
||||
{
|
||||
Mat4CpyMat4(bind_shape_matrix, (float (*)[4])skin.bind_shape_matrix);
|
||||
|
||||
transfer_array_data_const(skin.joints_per_vertex, joints_per_vertex);
|
||||
transfer_array_data_const(skin.weight_indices, weight_indices);
|
||||
transfer_array_data_const(skin.joint_indices, joint_indices);
|
||||
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) {}
|
||||
|
||||
// nobody owns the data after this, so it should be freed manually with releaseMemory
|
||||
void transfer_array_data(COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest)
|
||||
template <class T>
|
||||
void transfer_array_data(T& src, T& dest)
|
||||
{
|
||||
dest.setData((unsigned int*)src.getData(), src.getCount());
|
||||
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_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest)
|
||||
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();
|
||||
@@ -258,7 +365,7 @@ private:
|
||||
{
|
||||
transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointsPerVertex(), joints_per_vertex);
|
||||
transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getWeightIndices(), weight_indices);
|
||||
transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointIndices(), joint_indices);
|
||||
transfer_array_data((COLLADAFW::IntValuesArray&)skin->getJointIndices(), joint_indices);
|
||||
// transfer_array_data(skin->getWeights(), weights);
|
||||
|
||||
// cannot transfer data for FloatOrDoubleArray, copy values manually
|
||||
@@ -374,7 +481,7 @@ private:
|
||||
|
||||
// name group by joint node name
|
||||
if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) {
|
||||
name = get_dae_name(joint_by_uid[(*it).joint_uid]);
|
||||
name = get_joint_name(joint_by_uid[(*it).joint_uid]);
|
||||
}
|
||||
|
||||
add_defgroup_name(ob, (char*)name);
|
||||
@@ -410,6 +517,11 @@ private:
|
||||
ED_anim_dag_flush_update(C);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
|
||||
}
|
||||
|
||||
bPoseChannel *get_pose_channel_from_node(COLLADAFW::Node *node)
|
||||
{
|
||||
return get_pose_channel(ob_arm->pose, get_joint_name(node));
|
||||
}
|
||||
};
|
||||
|
||||
std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = skin controller data UID
|
||||
@@ -450,7 +562,7 @@ private:
|
||||
float obmat[4][4];
|
||||
|
||||
// object-space
|
||||
get_node_mat(obmat, node);
|
||||
get_node_mat(obmat, node, NULL, NULL);
|
||||
|
||||
// get world-space
|
||||
if (parent)
|
||||
@@ -460,7 +572,7 @@ private:
|
||||
}
|
||||
|
||||
// TODO rename from Node "name" attrs later
|
||||
EditBone *bone = addEditBone(arm, (char*)get_dae_name(node));
|
||||
EditBone *bone = addEditBone(arm, (char*)get_joint_name(node));
|
||||
totbone++;
|
||||
|
||||
if (parent) bone->parent = parent;
|
||||
@@ -476,6 +588,7 @@ private:
|
||||
if (parent && totchild == 1) {
|
||||
VecCopyf(parent->tail, bone->head);
|
||||
|
||||
// XXX increase this to prevent "very" small bones?
|
||||
const float epsilon = 0.000001f;
|
||||
|
||||
// derive leaf bone length
|
||||
@@ -539,67 +652,6 @@ private:
|
||||
leaf_bones.push_back(leaf);
|
||||
}
|
||||
|
||||
void get_node_mat(float mat[][4], COLLADAFW::Node *node)
|
||||
{
|
||||
float cur[4][4];
|
||||
float copy[4][4];
|
||||
|
||||
Mat4One(mat);
|
||||
|
||||
for (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:
|
||||
{
|
||||
COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm;
|
||||
COLLADABU::Math::Vector3& t = tra->getTranslation();
|
||||
|
||||
Mat4One(cur);
|
||||
cur[3][0] = (float)t[0];
|
||||
cur[3][1] = (float)t[1];
|
||||
cur[3][2] = (float)t[2];
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::ROTATE:
|
||||
{
|
||||
COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm;
|
||||
COLLADABU::Math::Vector3& raxis = ro->getRotationAxis();
|
||||
float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f);
|
||||
float axis[] = {raxis[0], raxis[1], raxis[2]};
|
||||
float quat[4];
|
||||
float rot_copy[3][3];
|
||||
float mat[3][3];
|
||||
AxisAngleToQuat(quat, axis, angle);
|
||||
|
||||
QuatToMat4(quat, cur);
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::SCALE:
|
||||
{
|
||||
COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale();
|
||||
float size[3] = {(float)s[0], (float)s[1], (float)s[2]};
|
||||
SizeToMat4(size, cur);
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::MATRIX:
|
||||
{
|
||||
unit_converter->mat4_from_dae(cur, ((COLLADAFW::Matrix*)tm)->getMatrix());
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::LOOKAT:
|
||||
case COLLADAFW::Transformation::SKEW:
|
||||
fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
Mat4CpyMat4(copy, mat);
|
||||
Mat4MulMat4(mat, cur, copy);
|
||||
}
|
||||
}
|
||||
|
||||
void fix_leaf_bones()
|
||||
{
|
||||
// just setting tail for leaf bones here
|
||||
@@ -634,7 +686,37 @@ private:
|
||||
fprintf(stderr, "Cannot find a pose channel for leaf bone %s\n", leaf.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_euler_rotmode()
|
||||
{
|
||||
// just set rotmode = PCHAN_ROT_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(joint)) {
|
||||
bPoseChannel *pchan = skin.get_pose_channel_from_node(joint);
|
||||
|
||||
if (pchan) {
|
||||
pchan->rotmode = PCHAN_ROT_EUL;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Cannot find pose channel for %s.\n", get_joint_name(joint));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object *get_empty_for_leaves()
|
||||
@@ -717,12 +799,15 @@ private:
|
||||
DAG_object_flush_update(scene, ob_arm, OB_RECALC_OB|OB_RECALC_DATA);
|
||||
|
||||
set_leaf_bone_shapes(ob_arm);
|
||||
|
||||
set_euler_rotmode();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
ArmatureImporter(UnitConverter *conv, MeshImporterBase *imp, Scene *sce) :
|
||||
unit_converter(conv), scene(sce), empty(NULL), mesh_importer(imp) {}
|
||||
TransformReader(conv), scene(sce), empty(NULL), mesh_importer(imp) {}
|
||||
|
||||
~ArmatureImporter()
|
||||
{
|
||||
@@ -752,7 +837,7 @@ public:
|
||||
}
|
||||
#ifdef COLLADA_DEBUG
|
||||
else {
|
||||
fprintf(stderr, "%s cannot be added to armature.\n", get_dae_name(node));
|
||||
fprintf(stderr, "%s cannot be added to armature.\n", get_joint_name(node));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -761,13 +846,6 @@ public:
|
||||
// here we add bones to armatures, having armatures previously created in write_controller
|
||||
void make_armatures(bContext *C)
|
||||
{
|
||||
#if 0
|
||||
std::vector<ArmatureJoints>::iterator it;
|
||||
|
||||
for (it = armature_joints.begin(); it != armature_joints.end(); it++) {
|
||||
create_armature_bones(*it);
|
||||
}
|
||||
#endif
|
||||
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
|
||||
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
|
||||
|
||||
@@ -873,6 +951,24 @@ public:
|
||||
|
||||
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(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.pose_channels[\"%s\"]", get_joint_name(node));
|
||||
}
|
||||
};
|
||||
|
||||
class MeshImporter : public MeshImporterBase
|
||||
@@ -1548,6 +1644,371 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class AnimationImporter : private TransformReader
|
||||
{
|
||||
private:
|
||||
|
||||
ArmatureImporter *armature_importer;
|
||||
Scene *scene;
|
||||
|
||||
std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > uid_fcurve_map;
|
||||
std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map;
|
||||
|
||||
void make_fcurves_from_animation(COLLADAFW::AnimationCurve *curve,
|
||||
COLLADAFW::FloatOrDoubleArray& input,
|
||||
COLLADAFW::FloatOrDoubleArray& output,
|
||||
COLLADAFW::FloatOrDoubleArray& intan,
|
||||
COLLADAFW::FloatOrDoubleArray& outtan, size_t dim, float fps)
|
||||
{
|
||||
int i;
|
||||
// char *path = "location";
|
||||
std::vector<FCurve*>& fcurves = uid_fcurve_map[curve->getUniqueId()];
|
||||
|
||||
if (dim == 1) {
|
||||
// create fcurve
|
||||
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 (i = 0; i < curve->getKeyCount(); i++) {
|
||||
BezTriple bez;
|
||||
memset(&bez, 0, sizeof(BezTriple));
|
||||
// intangent
|
||||
bez.vec[0][0] = get_float_value(intan, i + i) * fps;
|
||||
bez.vec[0][1] = get_float_value(intan, i + i + 1);
|
||||
// input, output
|
||||
bez.vec[1][0] = get_float_value(input, i) * fps;
|
||||
bez.vec[1][1] = get_float_value(output, i);
|
||||
// outtangent
|
||||
bez.vec[2][0] = get_float_value(outtan, i + i) * fps;
|
||||
bez.vec[2][1] = get_float_value(outtan, 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);
|
||||
calchandles_fcurve(fcu);
|
||||
}
|
||||
|
||||
fcurves.push_back(fcu);
|
||||
}
|
||||
else if(dim == 3) {
|
||||
for (i = 0; i < dim; i++ ) {
|
||||
// create fcurve
|
||||
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 (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 * 3 + 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);
|
||||
calchandles_fcurve(fcu);
|
||||
}
|
||||
|
||||
fcurves.push_back(fcu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index)
|
||||
{
|
||||
ID *id = &ob->id;
|
||||
bAction *act;
|
||||
|
||||
if (!ob->adt || !ob->adt->action)
|
||||
act = verify_adt_action(id, 1);
|
||||
else
|
||||
act = verify_adt_action(id, 0);
|
||||
|
||||
if (!ob->adt || !ob->adt->action) {
|
||||
fprintf(stderr, "Cannot create anim data or action for this object. \n");
|
||||
return;
|
||||
}
|
||||
|
||||
FCurve *fcu;
|
||||
std::vector<FCurve*>::iterator it;
|
||||
int i = 0;
|
||||
for (it = curves.begin(); it != curves.end(); it++) {
|
||||
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;
|
||||
|
||||
// convert degrees to radians for rotation
|
||||
char *p = strstr(rna_path, "rotation");
|
||||
if (p && *(p + strlen("rotation")) == '\0') {
|
||||
for(int j = 0; j < fcu->totvert; j++) {
|
||||
float rot_intan = fcu->bezt[j].vec[0][1];
|
||||
float rot_output = fcu->bezt[j].vec[1][1];
|
||||
float rot_outtan = fcu->bezt[j].vec[2][1];
|
||||
fcu->bezt[j].vec[0][1] = rot_intan * M_PI / 180.0f;
|
||||
fcu->bezt[j].vec[1][1] = rot_output * M_PI / 180.0f;
|
||||
fcu->bezt[j].vec[2][1] = rot_outtan * M_PI / 180.0f;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
BLI_addtail(&act->curves, fcu);
|
||||
}
|
||||
}
|
||||
public:
|
||||
|
||||
AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
|
||||
TransformReader(conv), armature_importer(arm), scene(scene) { }
|
||||
|
||||
bool write_animation( const COLLADAFW::Animation* anim )
|
||||
{
|
||||
float fps = (float)FPS;
|
||||
|
||||
if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
|
||||
COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim;
|
||||
size_t dim = curve->getOutDimension();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues();
|
||||
COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues();
|
||||
COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues();
|
||||
COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues();
|
||||
|
||||
// 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:
|
||||
// support this
|
||||
make_fcurves_from_animation(curve, input, output, intan, outtan, dim, fps);
|
||||
break;
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER:
|
||||
// and this
|
||||
make_fcurves_from_animation(curve, input, output, intan, outtan, dim, fps);
|
||||
break;
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_CARDINAL:
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_HERMITE:
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_BSPLINE:
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_STEP:
|
||||
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* animationList )
|
||||
{
|
||||
const COLLADAFW::UniqueId& anim_list_id = animationList->getUniqueId();
|
||||
|
||||
// possible in case we cannot interpret some transform
|
||||
if (uid_animated_map.find(anim_list_id) == uid_animated_map.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// for bones rna_path is like: pose.pose_channels["bone-name"].rotation
|
||||
|
||||
// what does this AnimationList animate?
|
||||
Animation& animated = uid_animated_map[anim_list_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 = animationList->getAnimationBindings();
|
||||
|
||||
switch (animated.tm->getTransformationType()) {
|
||||
case COLLADAFW::Transformation::TRANSLATE:
|
||||
{
|
||||
if (is_joint)
|
||||
BLI_snprintf(rna_path, sizeof(rna_path), "%s.location", joint_path);
|
||||
else
|
||||
BLI_strncpy(rna_path, "location", 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 (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) {
|
||||
fprintf(stderr, "Cannot find FCurve by animation UID.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<FCurve*>& fcurves = uid_fcurve_map[anim_uid];
|
||||
|
||||
switch (binding.animationClass) {
|
||||
case COLLADAFW::AnimationList::POSITION_X:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 0);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Y:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 1);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Z:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 2);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_XYZ:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, -1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "AnimationClass %d is not supported for TRANSLATE transformation.\n",
|
||||
binding.animationClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::ROTATE:
|
||||
{
|
||||
if (is_joint)
|
||||
BLI_snprintf(rna_path, sizeof(rna_path), "%s.euler_rotation", joint_path);
|
||||
else
|
||||
BLI_strncpy(rna_path, "rotation", 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 (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) {
|
||||
fprintf(stderr, "Cannot find FCurve by animation UID.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<FCurve*>& fcurves = uid_fcurve_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);
|
||||
}
|
||||
else if (COLLADABU::Math::Vector3::UNIT_Y == axis) {
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 1);
|
||||
}
|
||||
else if (COLLADABU::Math::Vector3::UNIT_Z == axis) {
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 2);
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::AnimationList::AXISANGLE:
|
||||
// convert axis-angle to quat? or XYZ?
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n",
|
||||
binding.animationClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::SCALE:
|
||||
{
|
||||
if (is_joint)
|
||||
BLI_snprintf(rna_path, sizeof(rna_path), "%s.scale", joint_path);
|
||||
else
|
||||
BLI_strncpy(rna_path, "scale", sizeof(rna_path));
|
||||
|
||||
// same as for TRANSLATE
|
||||
for (int i = 0; i < bindings.getCount(); i++) {
|
||||
const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
|
||||
COLLADAFW::UniqueId anim_uid = binding.animation;
|
||||
|
||||
if (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) {
|
||||
fprintf(stderr, "Cannot find FCurve by animation UID.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<FCurve*>& fcurves = uid_fcurve_map[anim_uid];
|
||||
|
||||
switch (binding.animationClass) {
|
||||
case COLLADAFW::AnimationList::POSITION_X:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 0);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Y:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 1);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Z:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, 2);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_XYZ:
|
||||
add_fcurves_to_object(ob, fcurves, rna_path, -1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "AnimationClass %d is not supported for TRANSLATE 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;
|
||||
}
|
||||
|
||||
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)
|
||||
TransformReader::decompose(mat, ob->loc, ob->rot, ob->size);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
COLLADA Importer limitations:
|
||||
@@ -1567,6 +2028,7 @@ private:
|
||||
UnitConverter unit_converter;
|
||||
ArmatureImporter armature_importer;
|
||||
MeshImporter mesh_importer;
|
||||
AnimationImporter anim_importer;
|
||||
|
||||
std::map<COLLADAFW::UniqueId, Image*> uid_image_map;
|
||||
std::map<COLLADAFW::UniqueId, Material*> uid_material_map;
|
||||
@@ -1577,21 +2039,17 @@ private:
|
||||
//std::map<COLLADAFW::TextureMapId, char*> set_layername_map;
|
||||
std::map<Material*, TexIndexTextureArrayMap> material_texture_mapping_map;
|
||||
// animation
|
||||
std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > uid_fcurve_map;
|
||||
struct AnimatedTransform {
|
||||
Object *ob;
|
||||
// COLLADAFW::Node *node;
|
||||
COLLADAFW::Transformation *tm; // which transform is animated by an AnimationList->id
|
||||
};
|
||||
// std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > uid_fcurve_map;
|
||||
// Nodes don't share AnimationLists (Arystan)
|
||||
std::map<COLLADAFW::UniqueId, AnimatedTransform> uid_animated_map; // AnimationList->uniqueId to AnimatedObject map
|
||||
// std::map<COLLADAFW::UniqueId, Animation> uid_animated_map; // AnimationList->uniqueId to AnimatedObject map
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor. */
|
||||
Writer(bContext *C, const char *filename) : mContext(C), mFilename(filename),
|
||||
armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C)),
|
||||
mesh_importer(&armature_importer, CTX_data_scene(C)) {};
|
||||
mesh_importer(&armature_importer, CTX_data_scene(C)),
|
||||
anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) {}
|
||||
|
||||
/** Destructor. */
|
||||
~Writer() {};
|
||||
@@ -1654,165 +2112,95 @@ public:
|
||||
|
||||
void write_node (COLLADAFW::Node *node, COLLADAFW::Node *parent_node, Scene *sce, Object *par)
|
||||
{
|
||||
// XXX linking object with the first <instance_geometry>, though a node may have more of them...
|
||||
// maybe join multiple <instance_...> meshes into 1, and link object with it? not sure...
|
||||
if (node->getType() != COLLADAFW::Node::NODE) {
|
||||
Object *ob = NULL;
|
||||
|
||||
if (node->getType() == COLLADAFW::Node::JOINT) {
|
||||
|
||||
if (node->getType() == COLLADAFW::Node::JOINT) {
|
||||
armature_importer.add_joint(node, parent_node == NULL || parent_node->getType() != COLLADAFW::Node::JOINT);
|
||||
}
|
||||
|
||||
COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
|
||||
for (int i = 0; i < child_nodes.getCount(); i++) {
|
||||
write_node(child_nodes[i], node, sce, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
COLLADAFW::InstanceGeometryPointerArray &geom = node->getInstanceGeometries();
|
||||
COLLADAFW::InstanceCameraPointerArray &camera = node->getInstanceCameras();
|
||||
COLLADAFW::InstanceLightPointerArray &lamp = node->getInstanceLights();
|
||||
COLLADAFW::InstanceControllerPointerArray &controller = node->getInstanceControllers();
|
||||
COLLADAFW::InstanceNodePointerArray &inst_node = node->getInstanceNodes();
|
||||
Object *ob = NULL;
|
||||
int k;
|
||||
|
||||
// <instance_geometry>
|
||||
if (geom.getCount() != 0) {
|
||||
ob = mesh_importer.create_mesh_object(node, geom[0], false, uid_material_map, material_texture_mapping_map);
|
||||
}
|
||||
// <instance_camera>
|
||||
else if (camera.getCount() != 0) {
|
||||
const COLLADAFW::UniqueId& cam_uid = camera[0]->getInstanciatedObjectId();
|
||||
if (uid_camera_map.find(cam_uid) == uid_camera_map.end()) {
|
||||
fprintf(stderr, "Couldn't find camera by UID. \n");
|
||||
return;
|
||||
}
|
||||
ob = add_object(sce, OB_CAMERA);
|
||||
Camera *cam = uid_camera_map[cam_uid];
|
||||
Camera *old_cam = (Camera*)ob->data;
|
||||
old_cam->id.us--;
|
||||
ob->data = cam;
|
||||
if (old_cam->id.us == 0) free_libblock(&G.main->camera, old_cam);
|
||||
}
|
||||
// <instance_light>
|
||||
else if (lamp.getCount() != 0) {
|
||||
const COLLADAFW::UniqueId& lamp_uid = lamp[0]->getInstanciatedObjectId();
|
||||
if (uid_lamp_map.find(lamp_uid) == uid_lamp_map.end()) {
|
||||
fprintf(stderr, "Couldn't find lamp by UID. \n");
|
||||
return;
|
||||
}
|
||||
ob = add_object(sce, OB_LAMP);
|
||||
Lamp *la = uid_lamp_map[lamp_uid];
|
||||
Lamp *old_lamp = (Lamp*)ob->data;
|
||||
old_lamp->id.us--;
|
||||
ob->data = la;
|
||||
if (old_lamp->id.us == 0) free_libblock(&G.main->lamp, old_lamp);
|
||||
}
|
||||
// <instance_controller>
|
||||
else if (controller.getCount() != 0) {
|
||||
COLLADAFW::InstanceController *geom = (COLLADAFW::InstanceController*)controller[0];
|
||||
ob = mesh_importer.create_mesh_object(node, geom, true, uid_material_map, material_texture_mapping_map);
|
||||
}
|
||||
// XXX <node> - this is not supported yet
|
||||
else if (inst_node.getCount() != 0) {
|
||||
return;
|
||||
}
|
||||
// if node is empty - create empty object
|
||||
// XXX empty node may not mean it is empty object, not sure about this
|
||||
else {
|
||||
ob = add_object(sce, OB_EMPTY);
|
||||
}
|
||||
// just checking if object wasn't created
|
||||
if (ob == NULL) return;
|
||||
// if par was given make this object child of the previous
|
||||
if (par != NULL) {
|
||||
Object workob;
|
||||
COLLADAFW::InstanceGeometryPointerArray &geom = node->getInstanceGeometries();
|
||||
COLLADAFW::InstanceCameraPointerArray &camera = node->getInstanceCameras();
|
||||
COLLADAFW::InstanceLightPointerArray &lamp = node->getInstanceLights();
|
||||
COLLADAFW::InstanceControllerPointerArray &controller = node->getInstanceControllers();
|
||||
COLLADAFW::InstanceNodePointerArray &inst_node = node->getInstanceNodes();
|
||||
|
||||
ob->parent = par;
|
||||
|
||||
// doing what 'set parent' operator does
|
||||
par->recalc |= OB_RECALC_OB;
|
||||
ob->parsubstr[0] = 0;
|
||||
|
||||
DAG_scene_sort(sce);
|
||||
// since ob->obmat is identity, this is not needed?
|
||||
/*what_does_parent(sce, ob, &workob);
|
||||
Mat4Invert(ob->parentinv, workob.obmat);
|
||||
|
||||
ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
|
||||
ob->partype = PAROBJECT;
|
||||
DAG_scene_sort(sce);*/
|
||||
}
|
||||
// transform Object
|
||||
float rot[3][3];
|
||||
Mat3One(rot);
|
||||
|
||||
// transform Object and store animation linking info
|
||||
// TODO: apply transforms sequentially and then extract location/scale/rotation from final matrix
|
||||
// this will be the correct way
|
||||
for (k = 0; k < node->getTransformations().getCount(); k ++) {
|
||||
|
||||
COLLADAFW::Transformation *tm = node->getTransformations()[k];
|
||||
COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
|
||||
|
||||
switch(type) {
|
||||
case COLLADAFW::Transformation::TRANSLATE:
|
||||
{
|
||||
COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm;
|
||||
COLLADABU::Math::Vector3& t = tra->getTranslation();
|
||||
ob->loc[0] = (float)t[0];
|
||||
ob->loc[1] = (float)t[1];
|
||||
ob->loc[2] = (float)t[2];
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::ROTATE:
|
||||
{
|
||||
COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm;
|
||||
COLLADABU::Math::Vector3& raxis = ro->getRotationAxis();
|
||||
float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f);
|
||||
float axis[] = {raxis[0], raxis[1], raxis[2]};
|
||||
float quat[4];
|
||||
float rot_copy[3][3];
|
||||
float mat[3][3];
|
||||
AxisAngleToQuat(quat, axis, angle);
|
||||
|
||||
QuatToMat3(quat, mat);
|
||||
Mat3CpyMat3(rot_copy, rot);
|
||||
Mat3MulMat3(rot, mat, rot_copy);
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::SCALE:
|
||||
{
|
||||
COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale();
|
||||
ob->size[0] = (float)s[0];
|
||||
ob->size[1] = (float)s[1];
|
||||
ob->size[2] = (float)s[2];
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::MATRIX:
|
||||
case COLLADAFW::Transformation::LOOKAT:
|
||||
case COLLADAFW::Transformation::SKEW:
|
||||
fprintf(stderr, "MATRIX, LOOKAT and SKEW transformations are not supported yet.\n");
|
||||
break;
|
||||
// XXX linking object with the first <instance_geometry>, though a node may have more of them...
|
||||
// maybe join multiple <instance_...> meshes into 1, and link object with it? not sure...
|
||||
// <instance_geometry>
|
||||
if (geom.getCount() != 0) {
|
||||
ob = mesh_importer.create_mesh_object(node, geom[0], false, uid_material_map, material_texture_mapping_map);
|
||||
}
|
||||
else if (camera.getCount() != 0) {
|
||||
const COLLADAFW::UniqueId& cam_uid = camera[0]->getInstanciatedObjectId();
|
||||
if (uid_camera_map.find(cam_uid) == uid_camera_map.end()) {
|
||||
fprintf(stderr, "Couldn't find camera by UID. \n");
|
||||
return;
|
||||
}
|
||||
ob = add_object(sce, OB_CAMERA);
|
||||
Camera *cam = uid_camera_map[cam_uid];
|
||||
Camera *old_cam = (Camera*)ob->data;
|
||||
old_cam->id.us--;
|
||||
ob->data = cam;
|
||||
if (old_cam->id.us == 0) free_libblock(&G.main->camera, old_cam);
|
||||
}
|
||||
else if (lamp.getCount() != 0) {
|
||||
const COLLADAFW::UniqueId& lamp_uid = lamp[0]->getInstanciatedObjectId();
|
||||
if (uid_lamp_map.find(lamp_uid) == uid_lamp_map.end()) {
|
||||
fprintf(stderr, "Couldn't find lamp by UID. \n");
|
||||
return;
|
||||
}
|
||||
ob = add_object(sce, OB_LAMP);
|
||||
Lamp *la = uid_lamp_map[lamp_uid];
|
||||
Lamp *old_lamp = (Lamp*)ob->data;
|
||||
old_lamp->id.us--;
|
||||
ob->data = la;
|
||||
if (old_lamp->id.us == 0) free_libblock(&G.main->lamp, old_lamp);
|
||||
}
|
||||
else if (controller.getCount() != 0) {
|
||||
COLLADAFW::InstanceController *geom = (COLLADAFW::InstanceController*)controller[0];
|
||||
ob = mesh_importer.create_mesh_object(node, geom, true, uid_material_map, material_texture_mapping_map);
|
||||
}
|
||||
// XXX instance_node is not supported yet
|
||||
else if (inst_node.getCount() != 0) {
|
||||
return;
|
||||
}
|
||||
// if node is empty - create empty object
|
||||
// XXX empty node may not mean it is empty object, not sure about this
|
||||
else {
|
||||
ob = add_object(sce, OB_EMPTY);
|
||||
}
|
||||
|
||||
// if par was given make this object child of the previous
|
||||
if (par && ob) {
|
||||
Object workob;
|
||||
|
||||
ob->parent = par;
|
||||
|
||||
// doing what 'set parent' operator does
|
||||
par->recalc |= OB_RECALC_OB;
|
||||
ob->parsubstr[0] = 0;
|
||||
|
||||
// AnimationList that drives this Transformation
|
||||
const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList();
|
||||
|
||||
// store this so later we can link animation data with ob
|
||||
AnimatedTransform anim = {ob, tm};
|
||||
this->uid_animated_map[anim_list_id] = anim;
|
||||
DAG_scene_sort(sce);
|
||||
// since ob->obmat is identity, this is not needed?
|
||||
/*what_does_parent(sce, ob, &workob);
|
||||
Mat4Invert(ob->parentinv, workob.obmat);
|
||||
|
||||
ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
|
||||
ob->partype = PAROBJECT;
|
||||
DAG_scene_sort(sce);*/
|
||||
}
|
||||
}
|
||||
Mat3ToEul(rot, ob->rot);
|
||||
|
||||
|
||||
anim_importer.read_node_transform(node, ob);
|
||||
|
||||
// if node has child nodes write them
|
||||
COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
|
||||
for (k = 0; k < child_nodes.getCount(); k++) {
|
||||
|
||||
COLLADAFW::Node *child_node = child_nodes[k];
|
||||
write_node(child_node, node, sce, ob);
|
||||
for (int i = 0; i < child_nodes.getCount(); i++) {
|
||||
write_node(child_nodes[i], node, sce, ob);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2148,318 +2536,16 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
float get_float(COLLADAFW::FloatOrDoubleArray array, int i)
|
||||
{
|
||||
switch(array.getType()) {
|
||||
case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
|
||||
{
|
||||
COLLADAFW::ArrayPrimitiveType<float> *values = array.getFloatValues();
|
||||
if (!values->empty())
|
||||
return (*values)[i];
|
||||
else return 0;
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
|
||||
{
|
||||
COLLADAFW::ArrayPrimitiveType<double> *values = array.getDoubleValues();
|
||||
if (!values->empty())
|
||||
return (float)(*values)[i];
|
||||
else return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_curves(const COLLADAFW::Animation* anim,
|
||||
COLLADAFW::AnimationCurve *curve,
|
||||
COLLADAFW::FloatOrDoubleArray input,
|
||||
COLLADAFW::FloatOrDoubleArray output,
|
||||
COLLADAFW::FloatOrDoubleArray intan,
|
||||
COLLADAFW::FloatOrDoubleArray outtan, size_t dim, float fps)
|
||||
{
|
||||
int i;
|
||||
char *path = "location";
|
||||
if (dim == 1) {
|
||||
// create fcurve
|
||||
FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
|
||||
if (!fcu) {
|
||||
fprintf(stderr, "Cannot create fcurve. \n");
|
||||
return;
|
||||
}
|
||||
|
||||
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 (i = 0; i < curve->getKeyCount(); i++) {
|
||||
BezTriple bez;
|
||||
memset(&bez, 0, sizeof(BezTriple));
|
||||
// intangent
|
||||
bez.vec[0][0] = get_float(intan, i + i) * fps;
|
||||
bez.vec[0][1] = get_float(intan, i + i + 1);
|
||||
// input, output
|
||||
bez.vec[1][0] = get_float(input, i) * fps;
|
||||
bez.vec[1][1] = get_float(output, i);
|
||||
// outtangent
|
||||
bez.vec[2][0] = get_float(outtan, i + i) * fps;
|
||||
bez.vec[2][1] = get_float(outtan, 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);
|
||||
calchandles_fcurve(fcu);
|
||||
}
|
||||
// map fcurve to animation's UID
|
||||
this->uid_fcurve_map[anim->getUniqueId()].push_back(fcu);
|
||||
}
|
||||
else if(dim == 3) {
|
||||
for (i = 0; i < dim; i++ ) {
|
||||
// create fcurve
|
||||
FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
|
||||
if (!fcu) {
|
||||
fprintf(stderr, "Cannot create fcurve. \n");
|
||||
continue;
|
||||
}
|
||||
|
||||
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 (int j = 0; j < curve->getKeyCount(); j++) {
|
||||
BezTriple bez;
|
||||
memset(&bez, 0, sizeof(BezTriple));
|
||||
// intangent
|
||||
bez.vec[0][0] = get_float(intan, j * 6 + i + i) * fps;
|
||||
bez.vec[0][1] = get_float(intan, j * 6 + i + i + 1);
|
||||
// input, output
|
||||
bez.vec[1][0] = get_float(input, j) * fps;
|
||||
bez.vec[1][1] = get_float(output, j * 3 + i);
|
||||
// outtangent
|
||||
bez.vec[2][0] = get_float(outtan, j * 6 + i + i) * fps;
|
||||
bez.vec[2][1] = get_float(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);
|
||||
calchandles_fcurve(fcu);
|
||||
}
|
||||
// map fcurve to animation's UID
|
||||
this->uid_fcurve_map[anim->getUniqueId()].push_back(fcu);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this function is called only for animations that pass COLLADAFW::validate
|
||||
virtual bool writeAnimation( const COLLADAFW::Animation* anim )
|
||||
{
|
||||
if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
|
||||
COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim;
|
||||
Scene *scene = CTX_data_scene(mContext);
|
||||
float fps = (float)FPS;
|
||||
// I wonder how do we use this (Arystan)
|
||||
size_t dim = curve->getOutDimension();
|
||||
|
||||
// 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;
|
||||
}
|
||||
COLLADAFW::FloatOrDoubleArray input = curve->getInputValues();
|
||||
COLLADAFW::FloatOrDoubleArray output = curve->getOutputValues();
|
||||
COLLADAFW::FloatOrDoubleArray intan = curve->getInTangentValues();
|
||||
COLLADAFW::FloatOrDoubleArray outtan = curve->getOutTangentValues();
|
||||
// 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:
|
||||
// support this
|
||||
write_curves(anim, curve, input, output, intan, outtan, dim, fps);
|
||||
break;
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER:
|
||||
// and this
|
||||
write_curves(anim, curve, input, output, intan, outtan, dim, fps);
|
||||
break;
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_CARDINAL:
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_HERMITE:
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_BSPLINE:
|
||||
case COLLADAFW::AnimationCurve::INTERPOLATION_STEP:
|
||||
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;
|
||||
}
|
||||
|
||||
void change_fcurve(Object *ob, const COLLADAFW::UniqueId& anim_id, char *rna_path, int array_index)
|
||||
{
|
||||
if (uid_fcurve_map.find(anim_id) == uid_fcurve_map.end()) {
|
||||
fprintf(stderr, "Cannot find fcurves by UID.\n");
|
||||
return;
|
||||
}
|
||||
ID *id = &ob->id;
|
||||
bAction *act;
|
||||
if (!ob->adt || !ob->adt->action)
|
||||
act = verify_adt_action(id, 1);
|
||||
else
|
||||
act = verify_adt_action(id, 0);
|
||||
if (!ob->adt || !ob->adt->action) {
|
||||
fprintf(stderr, "Cannot create anim data or action for this object. \n");
|
||||
return;
|
||||
}
|
||||
FCurve *fcu;
|
||||
std::vector<FCurve*> fcurves = uid_fcurve_map[anim_id];
|
||||
std::vector<FCurve*>::iterator it;
|
||||
int i = 0;
|
||||
for (it = fcurves.begin(); it != fcurves.end(); it++) {
|
||||
fcu = *it;
|
||||
strcpy(fcu->rna_path, rna_path);
|
||||
if (array_index == -1)
|
||||
fcu->array_index = i;
|
||||
else
|
||||
fcu->array_index = array_index;
|
||||
// convert degrees to radians for rotation
|
||||
if (strcmp(rna_path, "rotation") == 0) {
|
||||
for(int j = 0; j < fcu->totvert; j++) {
|
||||
float rot_intan = fcu->bezt[j].vec[0][1];
|
||||
float rot_output = fcu->bezt[j].vec[1][1];
|
||||
float rot_outtan = fcu->bezt[j].vec[2][1];
|
||||
fcu->bezt[j].vec[0][1] = rot_intan * M_PI / 180.0f;
|
||||
fcu->bezt[j].vec[1][1] = rot_output * M_PI / 180.0f;
|
||||
fcu->bezt[j].vec[2][1] = rot_outtan * M_PI / 180.0f;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
BLI_addtail(&act->curves, fcu);
|
||||
}
|
||||
return anim_importer.write_animation(anim);
|
||||
}
|
||||
|
||||
// called on post-process stage after writeVisualScenes
|
||||
virtual bool writeAnimationList( const COLLADAFW::AnimationList* animationList )
|
||||
{
|
||||
const COLLADAFW::UniqueId& anim_list_id = animationList->getUniqueId();
|
||||
|
||||
// possible in case we cannot interpret some transform
|
||||
if (uid_animated_map.find(anim_list_id) == uid_animated_map.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// what does this AnimationList animate?
|
||||
AnimatedTransform& animated = uid_animated_map[anim_list_id];
|
||||
char *loc = "location";
|
||||
char *rotate = "rotation";
|
||||
char *scale = "scale";
|
||||
Object *ob = animated.ob;
|
||||
|
||||
const COLLADAFW::AnimationList::AnimationBindings& bindings = animationList->getAnimationBindings();
|
||||
switch (animated.tm->getTransformationType()) {
|
||||
case COLLADAFW::Transformation::TRANSLATE:
|
||||
{
|
||||
for (int i = 0; i < bindings.getCount(); i++) {
|
||||
const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
|
||||
COLLADAFW::UniqueId anim_uid = binding.animation;
|
||||
|
||||
switch (binding.animationClass) {
|
||||
case COLLADAFW::AnimationList::POSITION_X:
|
||||
change_fcurve(ob, anim_uid, loc, 0);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Y:
|
||||
change_fcurve(ob, anim_uid, loc, 1);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Z:
|
||||
change_fcurve(ob, anim_uid, loc, 2);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_XYZ:
|
||||
change_fcurve(ob, anim_uid, loc, -1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "AnimationClass %d is not supported for TRANSLATE transformation.\n", binding.animationClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::ROTATE:
|
||||
{
|
||||
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;
|
||||
|
||||
switch (binding.animationClass) {
|
||||
case COLLADAFW::AnimationList::ANGLE:
|
||||
if (COLLADABU::Math::Vector3::UNIT_X == axis) {
|
||||
change_fcurve(ob, anim_uid, rotate, 0);
|
||||
}
|
||||
else if (COLLADABU::Math::Vector3::UNIT_Y == axis) {
|
||||
change_fcurve(ob, anim_uid, rotate, 1);
|
||||
}
|
||||
else if (COLLADABU::Math::Vector3::UNIT_Z == axis) {
|
||||
change_fcurve(ob, anim_uid, rotate, 2);
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::AnimationList::AXISANGLE:
|
||||
// convert axis-angle to quat? or XYZ?
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n",
|
||||
binding.animationClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COLLADAFW::Transformation::SCALE:
|
||||
{
|
||||
// same as for TRANSLATE
|
||||
for (int i = 0; i < bindings.getCount(); i++) {
|
||||
const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
|
||||
COLLADAFW::UniqueId anim_uid = binding.animation;
|
||||
|
||||
switch (binding.animationClass) {
|
||||
case COLLADAFW::AnimationList::POSITION_X:
|
||||
change_fcurve(ob, anim_uid, scale, 0);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Y:
|
||||
change_fcurve(ob, anim_uid, scale, 1);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_Z:
|
||||
change_fcurve(ob, anim_uid, scale, 2);
|
||||
break;
|
||||
case COLLADAFW::AnimationList::POSITION_XYZ:
|
||||
change_fcurve(ob, anim_uid, scale, -1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "AnimationClass %d is not supported for TRANSLATE 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;
|
||||
}
|
||||
|
||||
return true;
|
||||
return anim_importer.write_animation_list(animationList);
|
||||
}
|
||||
|
||||
/** When this method is called, the writer must write the skin controller data.
|
||||
|
||||
@@ -43,15 +43,26 @@ public:
|
||||
Mat4Transp(out);
|
||||
}
|
||||
|
||||
void mat4_to_dae(double out[][4], float in[][4])
|
||||
void mat4_to_dae_double(double out[][4], float in[][4])
|
||||
{
|
||||
float outf[4][4];
|
||||
float mat[4][4];
|
||||
|
||||
mat4_to_dae(outf, in);
|
||||
mat4_to_dae(mat, in);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
out[i][j] = outf[i][j];
|
||||
out[i][j] = mat[i][j];
|
||||
}
|
||||
};
|
||||
|
||||
class TransformBase
|
||||
{
|
||||
protected:
|
||||
void decompose(float mat[][4], float *loc, float *rot, float *size)
|
||||
{
|
||||
Mat4ToSize(mat, size);
|
||||
Mat4ToEul(mat, rot);
|
||||
VecCopyf(loc, mat[3]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user