These bits became obsolete with the new layer system, so we can simplify some code around them or avoid existing workarounds which were trying to keep things working for them. There are still work needed to be done for on_visible_change to avoid unnecessary updates, but that can also happen later.
1569 lines
43 KiB
C++
1569 lines
43 KiB
C++
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include "GeometryExporter.h"
|
|
#include "AnimationExporter.h"
|
|
#include "MaterialExporter.h"
|
|
|
|
template<class Functor>
|
|
void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
|
|
{
|
|
LinkNode *node;
|
|
for (node = export_set; node; node = node->next) {
|
|
Object *ob = (Object *)node->link;
|
|
f(ob);
|
|
}
|
|
}
|
|
|
|
bool AnimationExporter::exportAnimations(Scene *sce)
|
|
{
|
|
bool has_animations = hasAnimations(sce);
|
|
if (has_animations) {
|
|
this->scene = sce;
|
|
|
|
openLibrary();
|
|
|
|
forEachObjectInExportSet(sce, *this, this->export_settings->export_set);
|
|
|
|
closeLibrary();
|
|
}
|
|
return has_animations;
|
|
}
|
|
|
|
// called for each exported object
|
|
void AnimationExporter::operator()(Object *ob)
|
|
{
|
|
FCurve *fcu;
|
|
char *transformName;
|
|
/* bool isMatAnim = false; */ /* UNUSED */
|
|
|
|
//Export transform animations
|
|
if (ob->adt && ob->adt->action) {
|
|
fcu = (FCurve *)ob->adt->action->curves.first;
|
|
|
|
//transform matrix export for bones are temporarily disabled here.
|
|
if (ob->type == OB_ARMATURE) {
|
|
bArmature *arm = (bArmature *)ob->data;
|
|
for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
|
|
write_bone_animation_matrix(ob, bone);
|
|
}
|
|
|
|
while (fcu) {
|
|
//for armature animations as objects
|
|
if (ob->type == OB_ARMATURE)
|
|
transformName = fcu->rna_path;
|
|
else
|
|
transformName = extract_transform_name(fcu->rna_path);
|
|
|
|
if ((STREQ(transformName, "location") || STREQ(transformName, "scale")) ||
|
|
(STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
|
|
(STREQ(transformName, "rotation_quaternion")))
|
|
{
|
|
dae_animation(ob, fcu, transformName, false);
|
|
}
|
|
fcu = fcu->next;
|
|
}
|
|
|
|
}
|
|
|
|
export_object_constraint_animation(ob);
|
|
|
|
//This needs to be handled by extra profiles, so postponed for now
|
|
//export_morph_animation(ob);
|
|
|
|
//Export Lamp parameter animations
|
|
if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
|
|
fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
|
|
while (fcu) {
|
|
transformName = extract_transform_name(fcu->rna_path);
|
|
|
|
if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) ||
|
|
(STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance")))
|
|
{
|
|
dae_animation(ob, fcu, transformName, true);
|
|
}
|
|
fcu = fcu->next;
|
|
}
|
|
}
|
|
|
|
//Export Camera parameter animations
|
|
if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
|
|
fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
|
|
while (fcu) {
|
|
transformName = extract_transform_name(fcu->rna_path);
|
|
|
|
if ((STREQ(transformName, "lens")) ||
|
|
(STREQ(transformName, "ortho_scale")) ||
|
|
(STREQ(transformName, "clip_end")) ||
|
|
(STREQ(transformName, "clip_start")))
|
|
{
|
|
dae_animation(ob, fcu, transformName, true);
|
|
}
|
|
fcu = fcu->next;
|
|
}
|
|
}
|
|
|
|
//Export Material parameter animations.
|
|
for (int a = 0; a < ob->totcol; a++) {
|
|
Material *ma = give_current_material(ob, a + 1);
|
|
if (!ma) continue;
|
|
if (ma->adt && ma->adt->action) {
|
|
/* isMatAnim = true; */
|
|
fcu = (FCurve *)ma->adt->action->curves.first;
|
|
while (fcu) {
|
|
transformName = extract_transform_name(fcu->rna_path);
|
|
|
|
if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) ||
|
|
(STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) ||
|
|
(STREQ(transformName, "ior")))
|
|
{
|
|
dae_animation(ob, fcu, transformName, true, ma);
|
|
}
|
|
fcu = fcu->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AnimationExporter::export_object_constraint_animation(Object *ob)
|
|
{
|
|
std::vector<float> fra;
|
|
//Takes frames of target animations
|
|
make_anim_frames_from_targets(ob, fra);
|
|
|
|
if (fra.size())
|
|
dae_baked_object_animation(fra, ob);
|
|
}
|
|
|
|
void AnimationExporter::export_morph_animation(Object *ob)
|
|
{
|
|
FCurve *fcu;
|
|
char *transformName;
|
|
Key *key = BKE_key_from_object(ob);
|
|
if (!key) return;
|
|
|
|
if (key->adt && key->adt->action) {
|
|
fcu = (FCurve *)key->adt->action->curves.first;
|
|
|
|
while (fcu) {
|
|
transformName = extract_transform_name(fcu->rna_path);
|
|
|
|
dae_animation(ob, fcu, transformName, true);
|
|
|
|
fcu = fcu->next;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames )
|
|
{
|
|
ListBase *conlist = get_active_constraints(ob);
|
|
if (conlist == NULL) return;
|
|
bConstraint *con;
|
|
for (con = (bConstraint *)conlist->first; con; con = con->next) {
|
|
ListBase targets = {NULL, NULL};
|
|
|
|
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
|
|
|
if (!validateConstraints(con)) continue;
|
|
|
|
if (cti && cti->get_constraint_targets) {
|
|
bConstraintTarget *ct;
|
|
Object *obtar;
|
|
/* get targets
|
|
* - constraints should use ct->matrix, not directly accessing values
|
|
* - ct->matrix members have not yet been calculated here!
|
|
*/
|
|
cti->get_constraint_targets(con, &targets);
|
|
|
|
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
|
|
obtar = ct->tar;
|
|
|
|
if (obtar)
|
|
find_frames(obtar, frames);
|
|
}
|
|
|
|
if (cti->flush_constraint_targets)
|
|
cti->flush_constraint_targets(con, &targets, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//euler sources from quternion sources
|
|
float *AnimationExporter::get_eul_source_for_quat(Object *ob)
|
|
{
|
|
FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
|
|
const int keys = fcu->totvert;
|
|
float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
|
|
float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
|
|
float temp_quat[4];
|
|
float temp_eul[3];
|
|
while (fcu) {
|
|
char *transformName = extract_transform_name(fcu->rna_path);
|
|
|
|
if (STREQ(transformName, "rotation_quaternion") ) {
|
|
for (int i = 0; i < fcu->totvert; i++) {
|
|
*(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1];
|
|
}
|
|
}
|
|
fcu = fcu->next;
|
|
}
|
|
|
|
for (int i = 0; i < keys; i++) {
|
|
for (int j = 0; j < 4; j++)
|
|
temp_quat[j] = quat[(i * 4) + j];
|
|
|
|
quat_to_eul(temp_eul, temp_quat);
|
|
|
|
for (int k = 0; k < 3; k++)
|
|
eul[i * 3 + k] = temp_eul[k];
|
|
|
|
}
|
|
MEM_freeN(quat);
|
|
return eul;
|
|
|
|
}
|
|
|
|
//Get proper name for bones
|
|
std::string AnimationExporter::getObjectBoneName(Object *ob, const FCurve *fcu)
|
|
{
|
|
//hard-way to derive the bone name from rna_path. Must find more compact method
|
|
std::string rna_path = std::string(fcu->rna_path);
|
|
|
|
char *boneName = strtok((char *)rna_path.c_str(), "\"");
|
|
boneName = strtok(NULL, "\"");
|
|
|
|
if (boneName != NULL)
|
|
return /*id_name(ob) + "_" +*/ std::string(boneName);
|
|
else
|
|
return id_name(ob);
|
|
}
|
|
|
|
std::string AnimationExporter::getAnimationPathId(const FCurve *fcu)
|
|
{
|
|
std::string rna_path = std::string(fcu->rna_path);
|
|
return translate_id(rna_path);
|
|
}
|
|
|
|
//convert f-curves to animation curves and write
|
|
void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
|
|
{
|
|
const char *axis_name = NULL;
|
|
char anim_id[200];
|
|
|
|
bool has_tangents = false;
|
|
bool quatRotation = false;
|
|
|
|
if (STREQ(transformName, "rotation_quaternion") ) {
|
|
fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
|
|
quatRotation = true;
|
|
return;
|
|
}
|
|
|
|
//axis names for colors
|
|
else if (STREQ(transformName, "color") ||
|
|
STREQ(transformName, "specular_color") ||
|
|
STREQ(transformName, "diffuse_color") ||
|
|
STREQ(transformName, "alpha"))
|
|
{
|
|
const char *axis_names[] = {"R", "G", "B"};
|
|
if (fcu->array_index < 3)
|
|
axis_name = axis_names[fcu->array_index];
|
|
}
|
|
|
|
//axis names for transforms
|
|
else if (STREQ(transformName, "location") ||
|
|
STREQ(transformName, "scale") ||
|
|
STREQ(transformName, "rotation_euler") ||
|
|
STREQ(transformName, "rotation_quaternion"))
|
|
{
|
|
const char *axis_names[] = {"X", "Y", "Z"};
|
|
if (fcu->array_index < 3)
|
|
axis_name = axis_names[fcu->array_index];
|
|
}
|
|
else {
|
|
/* no axis name. single parameter */
|
|
axis_name = "";
|
|
}
|
|
|
|
std::string ob_name = std::string("null");
|
|
|
|
//Create anim Id
|
|
if (ob->type == OB_ARMATURE) {
|
|
ob_name = getObjectBoneName(ob, fcu);
|
|
BLI_snprintf(
|
|
anim_id,
|
|
sizeof(anim_id),
|
|
"%s_%s.%s",
|
|
(char *)translate_id(ob_name).c_str(),
|
|
(char *)translate_id(transformName).c_str(),
|
|
axis_name);
|
|
}
|
|
else {
|
|
if (ma)
|
|
ob_name = id_name(ob) + "_material";
|
|
else
|
|
ob_name = id_name(ob);
|
|
|
|
BLI_snprintf(
|
|
anim_id,
|
|
sizeof(anim_id),
|
|
"%s_%s_%s",
|
|
(char *)translate_id(ob_name).c_str(),
|
|
(char *)getAnimationPathId(fcu).c_str(),
|
|
axis_name);
|
|
}
|
|
|
|
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
|
|
|
|
// create input source
|
|
std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
|
|
|
|
// create output source
|
|
std::string output_id;
|
|
|
|
//quat rotations are skipped for now, because of complications with determining axis.
|
|
if (quatRotation) {
|
|
float *eul = get_eul_source_for_quat(ob);
|
|
float *eul_axis = (float *)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values");
|
|
for (int i = 0; i < fcu->totvert; i++) {
|
|
eul_axis[i] = eul[i * 3 + fcu->array_index];
|
|
}
|
|
output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name);
|
|
MEM_freeN(eul);
|
|
MEM_freeN(eul_axis);
|
|
}
|
|
else if (STREQ(transformName, "lens") && (ob->type == OB_CAMERA)) {
|
|
output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id);
|
|
}
|
|
else {
|
|
output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
|
|
}
|
|
|
|
// create interpolations source
|
|
std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
|
|
|
|
// handle tangents (if required)
|
|
std::string intangent_id;
|
|
std::string outtangent_id;
|
|
|
|
if (has_tangents) {
|
|
// create in_tangent source
|
|
intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name);
|
|
|
|
// create out_tangent source
|
|
outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name);
|
|
}
|
|
|
|
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
|
|
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
|
|
std::string empty;
|
|
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
|
|
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
|
|
|
|
// this input is required
|
|
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
|
|
|
|
if (has_tangents) {
|
|
sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
|
|
sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
|
|
}
|
|
|
|
addSampler(sampler);
|
|
|
|
std::string target;
|
|
|
|
if (!is_param)
|
|
target = translate_id(ob_name) +
|
|
"/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
|
|
else {
|
|
if (ob->type == OB_LAMP)
|
|
target = get_light_id(ob) +
|
|
"/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true);
|
|
|
|
if (ob->type == OB_CAMERA)
|
|
target = get_camera_id(ob) +
|
|
"/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true);
|
|
|
|
if (ma)
|
|
target = translate_id(id_name(ma)) + "-effect" +
|
|
"/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
|
|
//if shape key animation, this is the main problem, how to define the channel targets.
|
|
/*target = get_morph_id(ob) +
|
|
"/value" +*/
|
|
}
|
|
addChannel(COLLADABU::URI(empty, sampler_id), target);
|
|
|
|
closeAnimation();
|
|
}
|
|
|
|
|
|
|
|
//write bone animations in transform matrix sources
|
|
void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
|
|
{
|
|
if (!ob_arm->adt)
|
|
return;
|
|
|
|
//This will only export animations of bones in deform group.
|
|
/* if (!is_bone_deform_group(bone)) return; */
|
|
|
|
sample_and_write_bone_animation_matrix(ob_arm, bone);
|
|
|
|
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
|
|
write_bone_animation_matrix(ob_arm, child);
|
|
}
|
|
|
|
bool AnimationExporter::is_bone_deform_group(Bone *bone)
|
|
{
|
|
bool is_def;
|
|
//Check if current bone is deform
|
|
if ((bone->flag & BONE_NO_DEFORM) == 0) return true;
|
|
//Check child bones
|
|
else {
|
|
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
|
|
//loop through all the children until deform bone is found, and then return
|
|
is_def = is_bone_deform_group(child);
|
|
if (is_def) return true;
|
|
}
|
|
}
|
|
//no deform bone found in children also
|
|
return false;
|
|
}
|
|
|
|
void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone)
|
|
{
|
|
bArmature *arm = (bArmature *)ob_arm->data;
|
|
int flag = arm->flag;
|
|
std::vector<float> fra;
|
|
//char prefix[256];
|
|
|
|
//Check if there is a fcurve in the armature for the bone in param
|
|
//when baking this check is not needed, solve every bone for every frame.
|
|
/*FCurve *fcu = (FCurve *)ob_arm->adt->action->curves.first;
|
|
|
|
while (fcu) {
|
|
std::string bone_name = getObjectBoneName(ob_arm, fcu);
|
|
int val = BLI_strcasecmp((char *)bone_name.c_str(), bone->name);
|
|
if (val == 0) break;
|
|
fcu = fcu->next;
|
|
}
|
|
|
|
if (!(fcu)) return;*/
|
|
|
|
bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
|
|
if (!pchan)
|
|
return;
|
|
|
|
//every inserted keyframe of bones.
|
|
find_frames(ob_arm, fra);
|
|
|
|
if (flag & ARM_RESTPOS) {
|
|
arm->flag &= ~ARM_RESTPOS;
|
|
BKE_pose_where_is(scene, ob_arm);
|
|
}
|
|
|
|
if (fra.size()) {
|
|
dae_baked_animation(fra, ob_arm, bone);
|
|
}
|
|
|
|
if (flag & ARM_RESTPOS)
|
|
arm->flag = flag;
|
|
BKE_pose_where_is(scene, ob_arm);
|
|
}
|
|
|
|
void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone)
|
|
{
|
|
std::string ob_name = id_name(ob_arm);
|
|
std::string bone_name = bone->name;
|
|
char anim_id[200];
|
|
|
|
if (!fra.size())
|
|
return;
|
|
|
|
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
|
|
(char *)translate_id(bone_name).c_str(), "pose_matrix");
|
|
|
|
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
|
|
|
|
// create input source
|
|
std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
|
|
|
|
// create output source
|
|
std::string output_id;
|
|
|
|
output_id = create_4x4_source(fra, ob_arm, bone, anim_id);
|
|
|
|
// create interpolations source
|
|
std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
|
|
|
|
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
|
|
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
|
|
std::string empty;
|
|
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
|
|
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
|
|
|
|
// TODO create in/out tangents source
|
|
|
|
// this input is required
|
|
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
|
|
|
|
addSampler(sampler);
|
|
|
|
std::string target = translate_id(bone_name) + "/transform";
|
|
addChannel(COLLADABU::URI(empty, sampler_id), target);
|
|
|
|
closeAnimation();
|
|
}
|
|
|
|
void AnimationExporter::dae_baked_object_animation(std::vector<float> &fra, Object *ob)
|
|
{
|
|
std::string ob_name = id_name(ob);
|
|
char anim_id[200];
|
|
|
|
if (!fra.size())
|
|
return;
|
|
|
|
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s", (char *)translate_id(ob_name).c_str(),
|
|
"object_matrix");
|
|
|
|
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
|
|
|
|
// create input source
|
|
std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
|
|
|
|
// create output source
|
|
std::string output_id;
|
|
output_id = create_4x4_source( fra, ob, NULL, anim_id);
|
|
|
|
// create interpolations source
|
|
std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
|
|
|
|
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
|
|
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
|
|
std::string empty;
|
|
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
|
|
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
|
|
|
|
// TODO create in/out tangents source
|
|
|
|
// this input is required
|
|
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
|
|
|
|
addSampler(sampler);
|
|
|
|
std::string target = translate_id(ob_name) + "/transform";
|
|
addChannel(COLLADABU::URI(empty, sampler_id), target);
|
|
|
|
closeAnimation();
|
|
}
|
|
|
|
// dae_bone_animation -> add_bone_animation
|
|
// (blend this into dae_bone_animation)
|
|
void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name)
|
|
{
|
|
const char *axis_names[] = {"X", "Y", "Z"};
|
|
const char *axis_name = NULL;
|
|
char anim_id[200];
|
|
bool is_rot = tm_type == 0;
|
|
|
|
if (!fra.size())
|
|
return;
|
|
|
|
char rna_path[200];
|
|
BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
|
|
tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
|
|
|
|
if (axis > -1)
|
|
axis_name = axis_names[axis];
|
|
|
|
std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
|
|
|
|
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
|
|
(char *)translate_id(bone_name).c_str(), (char *)transform_sid.c_str());
|
|
|
|
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
|
|
|
|
// create input source
|
|
std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
|
|
|
|
// create output source
|
|
std::string output_id;
|
|
if (axis == -1)
|
|
output_id = create_xyz_source(values, fra.size(), anim_id);
|
|
else
|
|
output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
|
|
|
|
// create interpolations source
|
|
std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
|
|
|
|
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
|
|
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
|
|
std::string empty;
|
|
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
|
|
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
|
|
|
|
// TODO create in/out tangents source
|
|
|
|
// this input is required
|
|
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
|
|
|
|
addSampler(sampler);
|
|
|
|
std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
|
|
addChannel(COLLADABU::URI(empty, sampler_id), target);
|
|
|
|
closeAnimation();
|
|
}
|
|
|
|
float AnimationExporter::convert_time(float frame)
|
|
{
|
|
return FRA2TIME(frame);
|
|
}
|
|
|
|
float AnimationExporter::convert_angle(float angle)
|
|
{
|
|
return COLLADABU::Math::Utils::radToDegF(angle);
|
|
}
|
|
|
|
std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
|
|
{
|
|
switch (semantic) {
|
|
case COLLADASW::InputSemantic::INPUT:
|
|
return INPUT_SOURCE_ID_SUFFIX;
|
|
case COLLADASW::InputSemantic::OUTPUT:
|
|
return OUTPUT_SOURCE_ID_SUFFIX;
|
|
case COLLADASW::InputSemantic::INTERPOLATION:
|
|
return INTERPOLATION_SOURCE_ID_SUFFIX;
|
|
case COLLADASW::InputSemantic::IN_TANGENT:
|
|
return INTANGENT_SOURCE_ID_SUFFIX;
|
|
case COLLADASW::InputSemantic::OUT_TANGENT:
|
|
return OUTTANGENT_SOURCE_ID_SUFFIX;
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
|
|
COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
|
|
{
|
|
switch (semantic) {
|
|
case COLLADASW::InputSemantic::INPUT:
|
|
param.push_back("TIME");
|
|
break;
|
|
case COLLADASW::InputSemantic::OUTPUT:
|
|
if (is_rot) {
|
|
param.push_back("ANGLE");
|
|
}
|
|
else {
|
|
if (axis) {
|
|
param.push_back(axis);
|
|
}
|
|
else
|
|
if (transform) {
|
|
param.push_back("TRANSFORM");
|
|
}
|
|
else { //assumes if axis isn't specified all axises are added
|
|
param.push_back("X");
|
|
param.push_back("Y");
|
|
param.push_back("Z");
|
|
}
|
|
}
|
|
break;
|
|
case COLLADASW::InputSemantic::IN_TANGENT:
|
|
case COLLADASW::InputSemantic::OUT_TANGENT:
|
|
param.push_back("X");
|
|
param.push_back("Y");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length)
|
|
{
|
|
switch (semantic) {
|
|
case COLLADASW::InputSemantic::INPUT:
|
|
*length = 1;
|
|
values[0] = convert_time(bezt->vec[1][0]);
|
|
break;
|
|
case COLLADASW::InputSemantic::OUTPUT:
|
|
*length = 1;
|
|
if (is_angle) {
|
|
values[0] = RAD2DEGF(bezt->vec[1][1]);
|
|
}
|
|
else {
|
|
values[0] = bezt->vec[1][1];
|
|
}
|
|
break;
|
|
|
|
case COLLADASW::InputSemantic::IN_TANGENT:
|
|
*length = 2;
|
|
values[0] = convert_time(bezt->vec[0][0]);
|
|
if (bezt->ipo != BEZT_IPO_BEZ) {
|
|
// We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
|
|
values[0] = 0;
|
|
values[1] = 0;
|
|
}
|
|
else if (is_angle) {
|
|
values[1] = RAD2DEGF(bezt->vec[0][1]);
|
|
}
|
|
else {
|
|
values[1] = bezt->vec[0][1];
|
|
}
|
|
break;
|
|
|
|
case COLLADASW::InputSemantic::OUT_TANGENT:
|
|
*length = 2;
|
|
values[0] = convert_time(bezt->vec[2][0]);
|
|
if (bezt->ipo != BEZT_IPO_BEZ) {
|
|
// We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
|
|
values[0] = 0;
|
|
values[1] = 0;
|
|
}
|
|
else if (is_angle) {
|
|
values[1] = RAD2DEGF(bezt->vec[2][1]);
|
|
}
|
|
else {
|
|
values[1] = bezt->vec[2][1];
|
|
}
|
|
break;
|
|
default:
|
|
*length = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
|
|
{
|
|
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
|
|
|
//bool is_angle = STREQ(fcu->rna_path, "rotation");
|
|
bool is_angle = false;
|
|
|
|
if (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path,"spot_size")) is_angle = true;
|
|
|
|
COLLADASW::FloatSourceF source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(fcu->totvert);
|
|
|
|
switch (semantic) {
|
|
case COLLADASW::InputSemantic::INPUT:
|
|
case COLLADASW::InputSemantic::OUTPUT:
|
|
source.setAccessorStride(1);
|
|
break;
|
|
case COLLADASW::InputSemantic::IN_TANGENT:
|
|
case COLLADASW::InputSemantic::OUT_TANGENT:
|
|
source.setAccessorStride(2);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
add_source_parameters(param, semantic, is_angle, axis_name, false);
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
for (unsigned int i = 0; i < fcu->totvert; i++) {
|
|
float values[3]; // be careful!
|
|
int length = 0;
|
|
get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
|
|
for (int j = 0; j < length; j++)
|
|
source.appendValues(values[j]);
|
|
}
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
|
|
/*
|
|
* Similar to create_source_from_fcurve, but adds conversion of lens
|
|
* animation data from focal length to FOV.
|
|
*/
|
|
std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id)
|
|
{
|
|
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
|
|
|
COLLADASW::FloatSourceF source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(fcu->totvert);
|
|
|
|
source.setAccessorStride(1);
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
add_source_parameters(param, semantic, false, "", false);
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
for (unsigned int i = 0; i < fcu->totvert; i++) {
|
|
float values[3]; // be careful!
|
|
int length = 0;
|
|
get_source_values(&fcu->bezt[i], semantic, false, values, &length);
|
|
for (int j = 0; j < length; j++)
|
|
{
|
|
float val = RAD2DEGF(focallength_to_fov(values[j], cam->sensor_x));
|
|
source.appendValues(val);
|
|
}
|
|
}
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
|
|
|
|
|
|
//Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
|
|
std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
|
|
{
|
|
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
|
|
|
COLLADASW::FloatSourceF source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(tot);
|
|
source.setAccessorStride(1);
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
add_source_parameters(param, semantic, is_rot, axis_name, false);
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
for (int i = 0; i < tot; i++) {
|
|
float val = v[i];
|
|
////if (semantic == COLLADASW::InputSemantic::INPUT)
|
|
// val = convert_time(val);
|
|
//else
|
|
if (is_rot)
|
|
val = RAD2DEGF(val);
|
|
source.appendValues(val);
|
|
}
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
// only used for sources with INPUT semantic
|
|
std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
|
|
{
|
|
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
|
|
|
COLLADASW::FloatSourceF source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(fra.size());
|
|
source.setAccessorStride(1);
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
add_source_parameters(param, semantic, is_rot, axis_name, false);
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
std::vector<float>::iterator it;
|
|
for (it = fra.begin(); it != fra.end(); it++) {
|
|
float val = *it;
|
|
//if (semantic == COLLADASW::InputSemantic::INPUT)
|
|
val = convert_time(val);
|
|
/*else if (is_rot)
|
|
val = convert_angle(val);*/
|
|
source.appendValues(val);
|
|
}
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
|
|
|
|
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id)
|
|
{
|
|
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
|
|
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
|
|
|
COLLADASW::Float4x4Source source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(frames.size());
|
|
source.setAccessorStride(16);
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
add_source_parameters(param, semantic, false, NULL, true);
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
bPoseChannel *parchan = NULL;
|
|
bPoseChannel *pchan = NULL;
|
|
|
|
if (ob->type == OB_ARMATURE && bone) {
|
|
bPose *pose = ob->pose;
|
|
pchan = BKE_pose_channel_find_name(pose, bone->name);
|
|
if (!pchan)
|
|
return "";
|
|
|
|
parchan = pchan->parent;
|
|
|
|
enable_fcurves(ob->adt->action, bone->name);
|
|
}
|
|
|
|
std::vector<float>::iterator it;
|
|
int j = 0;
|
|
for (it = frames.begin(); it != frames.end(); it++) {
|
|
float mat[4][4], ipar[4][4];
|
|
|
|
float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
|
|
CFRA = BKE_scene_frame_get_from_ctime(scene, *it);
|
|
//BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene);
|
|
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
|
|
|
|
if (bone) {
|
|
if (pchan->flag & POSE_CHAIN) {
|
|
enable_fcurves(ob->adt->action, NULL);
|
|
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
|
|
BKE_pose_where_is(scene, ob);
|
|
}
|
|
else {
|
|
BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
|
|
}
|
|
|
|
// compute bone local mat
|
|
if (bone->parent) {
|
|
invert_m4_m4(ipar, parchan->pose_mat);
|
|
mul_m4_m4m4(mat, ipar, pchan->pose_mat);
|
|
}
|
|
else
|
|
copy_m4_m4(mat, pchan->pose_mat);
|
|
|
|
// OPEN_SIM_COMPATIBILITY
|
|
// AFAIK animation to second life is via BVH, but no
|
|
// reason to not have the collada-animation be correct
|
|
if (export_settings->open_sim) {
|
|
float temp[4][4];
|
|
copy_m4_m4(temp, bone->arm_mat);
|
|
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
|
|
invert_m4(temp);
|
|
|
|
mul_m4_m4m4(mat, mat, temp);
|
|
|
|
if (bone->parent) {
|
|
copy_m4_m4(temp, bone->parent->arm_mat);
|
|
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
|
|
|
|
mul_m4_m4m4(mat, temp, mat);
|
|
}
|
|
}
|
|
|
|
}
|
|
else {
|
|
calc_ob_mat_at_time(ob, ctime, mat);
|
|
}
|
|
|
|
UnitConverter converter;
|
|
|
|
double outmat[4][4];
|
|
converter.mat4_to_dae_double(outmat, mat);
|
|
|
|
source.appendValues(outmat);
|
|
|
|
j++;
|
|
|
|
BIK_release_tree(scene, ob, ctime);
|
|
}
|
|
|
|
if (ob->adt) {
|
|
enable_fcurves(ob->adt->action, NULL);
|
|
}
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
|
|
|
|
// only used for sources with OUTPUT semantic ( locations and scale)
|
|
std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
|
|
{
|
|
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
|
|
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
|
|
|
COLLADASW::FloatSourceF source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(tot);
|
|
source.setAccessorStride(3);
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
add_source_parameters(param, semantic, false, NULL, false);
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
for (int i = 0; i < tot; i++) {
|
|
source.appendValues(*v, *(v + 1), *(v + 2));
|
|
v += 3;
|
|
}
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
|
|
std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
|
|
{
|
|
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
|
|
|
|
COLLADASW::NameSource source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(fcu->totvert);
|
|
source.setAccessorStride(1);
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
param.push_back("INTERPOLATION");
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
*has_tangents = false;
|
|
|
|
for (unsigned int i = 0; i < fcu->totvert; i++) {
|
|
if (fcu->bezt[i].ipo == BEZT_IPO_BEZ) {
|
|
source.appendValues(BEZIER_NAME);
|
|
*has_tangents = true;
|
|
}
|
|
else if (fcu->bezt[i].ipo == BEZT_IPO_CONST) {
|
|
source.appendValues(STEP_NAME);
|
|
}
|
|
else { // BEZT_IPO_LIN
|
|
source.appendValues(LINEAR_NAME);
|
|
}
|
|
}
|
|
// unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
|
|
std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
|
|
{
|
|
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
|
|
|
|
COLLADASW::NameSource source(mSW);
|
|
source.setId(source_id);
|
|
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
|
source.setAccessorCount(tot);
|
|
source.setAccessorStride(1);
|
|
|
|
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
|
param.push_back("INTERPOLATION");
|
|
|
|
source.prepareToAppendValues();
|
|
|
|
for (int i = 0; i < tot; i++) {
|
|
source.appendValues(LINEAR_NAME);
|
|
}
|
|
|
|
source.finish();
|
|
|
|
return source_id;
|
|
}
|
|
|
|
std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
|
|
{
|
|
std::string tm_name;
|
|
// when given rna_path, determine tm_type from it
|
|
if (rna_path) {
|
|
char *name = extract_transform_name(rna_path);
|
|
|
|
if (STREQ(name, "color"))
|
|
tm_type = 1;
|
|
else if (STREQ(name, "spot_size"))
|
|
tm_type = 2;
|
|
else if (STREQ(name, "spot_blend"))
|
|
tm_type = 3;
|
|
else if (STREQ(name, "distance"))
|
|
tm_type = 4;
|
|
else
|
|
tm_type = -1;
|
|
}
|
|
|
|
switch (tm_type) {
|
|
case 1:
|
|
tm_name = "color";
|
|
break;
|
|
case 2:
|
|
tm_name = "fall_off_angle";
|
|
break;
|
|
case 3:
|
|
tm_name = "fall_off_exponent";
|
|
break;
|
|
case 4:
|
|
tm_name = "blender/blender_dist";
|
|
break;
|
|
|
|
default:
|
|
tm_name = "";
|
|
break;
|
|
}
|
|
|
|
if (tm_name.size()) {
|
|
if (axis_name[0])
|
|
return tm_name + "." + std::string(axis_name);
|
|
else
|
|
return tm_name;
|
|
}
|
|
|
|
return std::string("");
|
|
}
|
|
|
|
std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
|
|
{
|
|
std::string tm_name;
|
|
// when given rna_path, determine tm_type from it
|
|
if (rna_path) {
|
|
char *name = extract_transform_name(rna_path);
|
|
|
|
if (STREQ(name, "lens"))
|
|
tm_type = 0;
|
|
else if (STREQ(name, "ortho_scale"))
|
|
tm_type = 1;
|
|
else if (STREQ(name, "clip_end"))
|
|
tm_type = 2;
|
|
else if (STREQ(name, "clip_start"))
|
|
tm_type = 3;
|
|
|
|
else
|
|
tm_type = -1;
|
|
}
|
|
|
|
switch (tm_type) {
|
|
case 0:
|
|
tm_name = "xfov";
|
|
break;
|
|
case 1:
|
|
tm_name = "xmag";
|
|
break;
|
|
case 2:
|
|
tm_name = "zfar";
|
|
break;
|
|
case 3:
|
|
tm_name = "znear";
|
|
break;
|
|
|
|
default:
|
|
tm_name = "";
|
|
break;
|
|
}
|
|
|
|
if (tm_name.size()) {
|
|
if (axis_name[0])
|
|
return tm_name + "." + std::string(axis_name);
|
|
else
|
|
return tm_name;
|
|
}
|
|
|
|
return std::string("");
|
|
}
|
|
|
|
// Assign sid of the animated parameter or transform
|
|
// for rotation, axis name is always appended and the value of append_axis is ignored
|
|
std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
|
|
{
|
|
std::string tm_name;
|
|
bool is_angle = false;
|
|
// when given rna_path, determine tm_type from it
|
|
if (rna_path) {
|
|
char *name = extract_transform_name(rna_path);
|
|
|
|
if (STREQ(name, "rotation_euler"))
|
|
tm_type = 0;
|
|
else if (STREQ(name, "rotation_quaternion"))
|
|
tm_type = 1;
|
|
else if (STREQ(name, "scale"))
|
|
tm_type = 2;
|
|
else if (STREQ(name, "location"))
|
|
tm_type = 3;
|
|
else if (STREQ(name, "specular_hardness"))
|
|
tm_type = 4;
|
|
else if (STREQ(name, "specular_color"))
|
|
tm_type = 5;
|
|
else if (STREQ(name, "diffuse_color"))
|
|
tm_type = 6;
|
|
else if (STREQ(name, "alpha"))
|
|
tm_type = 7;
|
|
else if (STREQ(name, "ior"))
|
|
tm_type = 8;
|
|
|
|
else
|
|
tm_type = -1;
|
|
}
|
|
|
|
switch (tm_type) {
|
|
case 0:
|
|
case 1:
|
|
tm_name = "rotation";
|
|
is_angle = true;
|
|
break;
|
|
case 2:
|
|
tm_name = "scale";
|
|
break;
|
|
case 3:
|
|
tm_name = "location";
|
|
break;
|
|
case 4:
|
|
tm_name = "shininess";
|
|
break;
|
|
case 5:
|
|
tm_name = "specular";
|
|
break;
|
|
case 6:
|
|
tm_name = "diffuse";
|
|
break;
|
|
case 7:
|
|
tm_name = "transparency";
|
|
break;
|
|
case 8:
|
|
tm_name = "index_of_refraction";
|
|
break;
|
|
|
|
default:
|
|
tm_name = "";
|
|
break;
|
|
}
|
|
|
|
if (tm_name.size()) {
|
|
if (is_angle)
|
|
return tm_name + std::string(axis_name) + ".ANGLE";
|
|
else
|
|
if (axis_name[0])
|
|
return tm_name + "." + std::string(axis_name);
|
|
else
|
|
return tm_name;
|
|
}
|
|
|
|
return std::string("");
|
|
}
|
|
|
|
char *AnimationExporter::extract_transform_name(char *rna_path)
|
|
{
|
|
char *dot = strrchr(rna_path, '.');
|
|
return dot ? (dot + 1) : rna_path;
|
|
}
|
|
|
|
//find keyframes of all the objects animations
|
|
void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra)
|
|
{
|
|
if (ob->adt && ob->adt->action) {
|
|
FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
|
|
|
|
for (; fcu; fcu = fcu->next) {
|
|
for (unsigned int i = 0; i < fcu->totvert; i++) {
|
|
float f = fcu->bezt[i].vec[1][0];
|
|
if (std::find(fra.begin(), fra.end(), f) == fra.end())
|
|
fra.push_back(f);
|
|
}
|
|
}
|
|
|
|
// keep the keys in ascending order
|
|
std::sort(fra.begin(), fra.end());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// enable fcurves driving a specific bone, disable all the rest
|
|
// if bone_name = NULL enable all fcurves
|
|
void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
|
|
{
|
|
FCurve *fcu;
|
|
char prefix[200];
|
|
|
|
if (bone_name)
|
|
BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
|
|
|
|
for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
|
|
if (bone_name) {
|
|
if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
|
|
fcu->flag &= ~FCURVE_DISABLED;
|
|
else
|
|
fcu->flag |= FCURVE_DISABLED;
|
|
}
|
|
else {
|
|
fcu->flag &= ~FCURVE_DISABLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool AnimationExporter::hasAnimations(Scene *sce)
|
|
{
|
|
LinkNode *node;
|
|
|
|
for (node=this->export_settings->export_set; node; node=node->next) {
|
|
Object *ob = (Object *)node->link;
|
|
|
|
FCurve *fcu = 0;
|
|
//Check for object transform animations
|
|
if (ob->adt && ob->adt->action)
|
|
fcu = (FCurve *)ob->adt->action->curves.first;
|
|
//Check for Lamp parameter animations
|
|
else if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action)
|
|
fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
|
|
//Check for Camera parameter animations
|
|
else if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action)
|
|
fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
|
|
|
|
//Check Material Effect parameter animations.
|
|
for (int a = 0; a < ob->totcol; a++) {
|
|
Material *ma = give_current_material(ob, a + 1);
|
|
if (!ma) continue;
|
|
if (ma->adt && ma->adt->action) {
|
|
fcu = (FCurve *)ma->adt->action->curves.first;
|
|
}
|
|
}
|
|
|
|
//check shape key animation
|
|
if (!fcu) {
|
|
Key *key = BKE_key_from_object(ob);
|
|
if (key && key->adt && key->adt->action)
|
|
fcu = (FCurve *)key->adt->action->curves.first;
|
|
}
|
|
if (fcu)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//------------------------------- Not used in the new system.--------------------------------------------------------
|
|
void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
|
|
{
|
|
if (rotmode > 0)
|
|
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)
|
|
;*/
|
|
}
|
|
|
|
void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
|
|
{
|
|
if (ob->adt && ob->adt->action) {
|
|
FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
|
|
|
|
for (; fcu; fcu = fcu->next) {
|
|
if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix)))
|
|
continue;
|
|
|
|
char *name = extract_transform_name(fcu->rna_path);
|
|
if (STREQ(name, tm_name)) {
|
|
for (unsigned int i = 0; i < fcu->totvert; i++) {
|
|
float f = fcu->bezt[i].vec[1][0];
|
|
if (std::find(fra.begin(), fra.end(), f) == fra.end())
|
|
fra.push_back(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
// keep the keys in ascending order
|
|
std::sort(fra.begin(), fra.end());
|
|
}
|
|
}
|
|
|
|
void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone)
|
|
{
|
|
if (!ob_arm->adt)
|
|
return;
|
|
|
|
//write bone animations for 3 transform types
|
|
//i=0 --> rotations
|
|
//i=1 --> scale
|
|
//i=2 --> location
|
|
for (int i = 0; i < 3; i++)
|
|
sample_and_write_bone_animation(ob_arm, bone, i);
|
|
|
|
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
|
|
write_bone_animation(ob_arm, child);
|
|
}
|
|
|
|
void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
|
|
{
|
|
bArmature *arm = (bArmature *)ob_arm->data;
|
|
int flag = arm->flag;
|
|
std::vector<float> fra;
|
|
char prefix[256];
|
|
|
|
BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
|
|
|
|
bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
|
|
if (!pchan)
|
|
return;
|
|
//Fill frame array with key frame values framed at \param:transform_type
|
|
switch (transform_type) {
|
|
case 0:
|
|
find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
|
|
break;
|
|
case 1:
|
|
find_frames(ob_arm, fra, prefix, "scale");
|
|
break;
|
|
case 2:
|
|
find_frames(ob_arm, fra, prefix, "location");
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// exit rest position
|
|
if (flag & ARM_RESTPOS) {
|
|
arm->flag &= ~ARM_RESTPOS;
|
|
BKE_pose_where_is(scene, ob_arm);
|
|
}
|
|
//v array will hold all values which will be exported.
|
|
if (fra.size()) {
|
|
float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
|
|
sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
|
|
|
|
if (transform_type == 0) {
|
|
// write x, y, z curves separately if it is rotation
|
|
float *axisValues = (float *)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
for (unsigned int j = 0; j < fra.size(); j++)
|
|
axisValues[j] = values[j * 3 + i];
|
|
|
|
dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
|
|
}
|
|
MEM_freeN(axisValues);
|
|
}
|
|
else {
|
|
// write xyz at once if it is location or scale
|
|
dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
|
|
}
|
|
|
|
MEM_freeN(values);
|
|
}
|
|
|
|
// restore restpos
|
|
if (flag & ARM_RESTPOS)
|
|
arm->flag = flag;
|
|
BKE_pose_where_is(scene, ob_arm);
|
|
}
|
|
|
|
void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
|
|
{
|
|
bPoseChannel *parchan = NULL;
|
|
bPose *pose = ob_arm->pose;
|
|
|
|
pchan = BKE_pose_channel_find_name(pose, bone->name);
|
|
|
|
if (!pchan)
|
|
return;
|
|
|
|
parchan = pchan->parent;
|
|
|
|
enable_fcurves(ob_arm->adt->action, bone->name);
|
|
|
|
std::vector<float>::iterator it;
|
|
for (it = frames.begin(); it != frames.end(); it++) {
|
|
float mat[4][4], ipar[4][4];
|
|
|
|
float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
|
|
|
|
|
|
BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
|
|
BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1);
|
|
|
|
// compute bone local mat
|
|
if (bone->parent) {
|
|
invert_m4_m4(ipar, parchan->pose_mat);
|
|
mul_m4_m4m4(mat, ipar, pchan->pose_mat);
|
|
}
|
|
else
|
|
copy_m4_m4(mat, pchan->pose_mat);
|
|
|
|
switch (type) {
|
|
case 0:
|
|
mat4_to_eul(v, mat);
|
|
break;
|
|
case 1:
|
|
mat4_to_size(v, mat);
|
|
break;
|
|
case 2:
|
|
copy_v3_v3(v, mat[3]);
|
|
break;
|
|
}
|
|
|
|
v += 3;
|
|
}
|
|
|
|
enable_fcurves(ob_arm->adt->action, NULL);
|
|
}
|
|
|
|
bool AnimationExporter::validateConstraints(bConstraint *con)
|
|
{
|
|
bool valid = true;
|
|
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
|
/* these we can skip completely (invalid constraints...) */
|
|
if (cti == NULL) valid = false;
|
|
if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) valid = false;
|
|
/* these constraints can't be evaluated anyway */
|
|
if (cti->evaluate_constraint == NULL) valid = false;
|
|
/* influence == 0 should be ignored */
|
|
if (con->enforce == 0.0f) valid = false;
|
|
|
|
return valid;
|
|
}
|
|
|
|
void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4])
|
|
{
|
|
ListBase *conlist = get_active_constraints(ob);
|
|
bConstraint *con;
|
|
for (con = (bConstraint *)conlist->first; con; con = con->next) {
|
|
ListBase targets = {NULL, NULL};
|
|
|
|
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
|
|
|
if (cti && cti->get_constraint_targets) {
|
|
bConstraintTarget *ct;
|
|
Object *obtar;
|
|
cti->get_constraint_targets(con, &targets);
|
|
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
|
|
obtar = ct->tar;
|
|
|
|
if (obtar) {
|
|
BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
|
|
BKE_object_where_is_calc_time(scene, obtar, ctime);
|
|
}
|
|
}
|
|
|
|
if (cti->flush_constraint_targets)
|
|
cti->flush_constraint_targets(con, &targets, 1);
|
|
}
|
|
}
|
|
BKE_object_where_is_calc_time(scene, ob, ctime);
|
|
copy_m4_m4(mat, ob->obmat);
|
|
}
|
|
|