Changeset View
Changeset View
Standalone View
Standalone View
source/blender/collada/AnimationExporter.cpp
| Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (has_animations) { | ||||
| forEachObjectInExportSet(sce, *this, this->export_settings->export_set); | forEachObjectInExportSet(sce, *this, this->export_settings->export_set); | ||||
| closeLibrary(); | closeLibrary(); | ||||
| } | } | ||||
| return has_animations; | return has_animations; | ||||
| } | } | ||||
| // called for each exported object | |||||
| void AnimationExporter::operator()(Object *ob) | /* | ||||
| * This function creates a complete LINEAR Collada <Animation> Entry with all needed | |||||
| * <source>, <sampler>, and <channel> entries. | |||||
| * This is is used for creating sampled Transformation Animations for either: | |||||
| * | |||||
| * 1-axis animation: | |||||
| * times contains the time points in seconds from within the timeline | |||||
| * values contains the data (list of single floats) | |||||
| * channel_count = 1 | |||||
| * axis_name = ['X' | 'Y' | 'Z'] | |||||
| * is_rot indicates if the animation is a rotation | |||||
| * | |||||
| * 3-axis animation: | |||||
| * times contains the time points in seconds from within the timeline | |||||
| * values contains the data (list of floats where each 3 entries are one vector) | |||||
| * channel_count = 3 | |||||
| * axis_name = "" (actually not used) | |||||
| * is_rot = false (see xxx below) | |||||
| * | |||||
| * xxx: I tried to create a 3 axis rotation animation | |||||
| * like for translation or scale. But i could not | |||||
| * figure out how to setup the channel for this case. | |||||
| * So for now rotations are exported as 3 separate 1-axis collada animations | |||||
| * See export_sampled_animation() further down. | |||||
| */ | |||||
| void AnimationExporter::create_sampled_animation(int channel_count, | |||||
| std::vector<float> ×, | |||||
| std::vector<float> &values, | |||||
| std::string ob_name, | |||||
| std::string label, | |||||
| std::string axis_name, | |||||
| bool is_rot) | |||||
| { | { | ||||
| FCurve *fcu; | |||||
| char *transformName; | |||||
| /* bool isMatAnim = false; */ /* UNUSED */ | |||||
| //Export transform animations | char anim_id[200]; | ||||
| if (ob->adt && ob->adt->action) { | |||||
| fcu = (FCurve *)ob->adt->action->curves.first; | BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), label.c_str(), axis_name.c_str()); | ||||
| openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); | |||||
| /* create input source */ | |||||
| std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, times, false, anim_id, ""); | |||||
| /* create output source */ | |||||
| std::string output_id; | |||||
| if (channel_count == 1) | |||||
| output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, &values[0], values.size(), is_rot, anim_id, axis_name.c_str()); | |||||
| else if(channel_count = 3) | |||||
| output_id = create_xyz_source(&values[0], times.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 (LINEAR) */ | |||||
| std::string interpolation_id = fake_interpolation_source(times.size(), anim_id, ""); | |||||
| /* Create Sampler */ | |||||
| sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); | |||||
| addSampler(sampler); | |||||
| /* Create channel */ | |||||
| std::string target = translate_id(ob_name) + "/" + label + axis_name + ((is_rot) ? ".ANGLE" : ""); | |||||
| addChannel(COLLADABU::URI(empty, sampler_id), target); | |||||
| closeAnimation(); | |||||
| //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); | |||||
| } | } | ||||
| /* | |||||
| * Export all animation FCurves of an Object. | |||||
| * | |||||
| * Note: This uses the keyframes as sample points, | |||||
| * and exports "baked keyframes" while keeping the tangent infromation | |||||
| * of the FCurves intact. This works for simple cases, but breaks | |||||
| * especially when negative scales are involved in the animation. | |||||
| * | |||||
| * If it is necessary to conserve the Animation precisely then | |||||
| * use export_sampled_animation_set() instead. | |||||
| */ | |||||
| void AnimationExporter::export_keyframed_animation_set(Object *ob) | |||||
| { | |||||
| FCurve *fcu = (FCurve *)ob->adt->action->curves.first; | |||||
| char *transformName; | |||||
| while (fcu) { | while (fcu) { | ||||
| //for armature animations as objects | //for armature animations as objects | ||||
| if (ob->type == OB_ARMATURE) | if (ob->type == OB_ARMATURE) | ||||
| transformName = fcu->rna_path; | transformName = fcu->rna_path; | ||||
| else | else | ||||
| transformName = extract_transform_name(fcu->rna_path); | transformName = extract_transform_name(fcu->rna_path); | ||||
| if ((STREQ(transformName, "location") || STREQ(transformName, "scale")) || | if ( | ||||
| STREQ(transformName, "location") || | |||||
| STREQ(transformName, "scale") || | |||||
| (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) || | (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) || | ||||
| (STREQ(transformName, "rotation_quaternion"))) | STREQ(transformName, "rotation_quaternion")) | ||||
| { | { | ||||
| dae_animation(ob, fcu, transformName, false); | create_keyframed_animation(ob, fcu, transformName, false); | ||||
| } | } | ||||
| fcu = fcu->next; | fcu = fcu->next; | ||||
| } | } | ||||
| } | } | ||||
| /* | |||||
| * Export the sampled animation of an Object. | |||||
| * | |||||
| * Note: This steps over all animation frames (step size is given in export_settings.sample_size) | |||||
| * and then evaluates the transformation, | |||||
| * and exports "baked samples" This works always, however currently the interpolation type is set | |||||
| * to LINEAR for now. (maybe later this can be changed to BEZIER) | |||||
| * | |||||
| * Note: If it is necessary to keep the FCurves intact, then use export_keyframed_animation_set() instead. | |||||
| * However be aware that exporting keyframed animation may modify the animation slightly. | |||||
| * Also keyframed animation exports tend to break when negative scales are involved. | |||||
| */ | |||||
| void AnimationExporter::export_sampled_animation_set(Object *ob) | |||||
| { | |||||
| static int LOC = 0; | |||||
| static int EULX = 1; | |||||
| static int EULY = 2; | |||||
| static int EULZ = 3; | |||||
| static int SCALE = 4; | |||||
| static int TIME = 5; | |||||
| if (this->export_settings->sampling_rate < 1) | |||||
| return; // to avoid infinite loop | |||||
| std::vector<float> baked_curves[6]; | |||||
| std::vector<float> &ctimes = baked_curves[TIME]; | |||||
| find_sampleframes(ob, ctimes); | |||||
| for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime ) { | |||||
| float fmat[4][4]; | |||||
| float floc[3]; | |||||
| float fquat[4]; | |||||
| float fsize[3]; | |||||
| float feul[3]; | |||||
| evaluate_anim_with_constraints(ob, *ctime); // set object transforms to the frame | |||||
| BKE_object_matrix_local_get(ob, fmat); | |||||
| mat4_decompose(floc, fquat, fsize, fmat); | |||||
| quat_to_eul(feul, fquat); | |||||
| baked_curves[LOC].push_back(floc[0]); | |||||
| baked_curves[LOC].push_back(floc[1]); | |||||
| baked_curves[LOC].push_back(floc[2]); | |||||
| baked_curves[EULX].push_back(feul[0]); | |||||
| baked_curves[EULY].push_back(feul[1]); | |||||
| baked_curves[EULZ].push_back(feul[2]); | |||||
| baked_curves[SCALE].push_back(fsize[0]); | |||||
| baked_curves[SCALE].push_back(fsize[1]); | |||||
| baked_curves[SCALE].push_back(fsize[2]); | |||||
| } | |||||
| std::string ob_name = id_name(ob); | |||||
| create_sampled_animation(3, baked_curves[TIME], baked_curves[SCALE], ob_name, "scale", "", false); | |||||
| create_sampled_animation(3, baked_curves[TIME], baked_curves[LOC], ob_name, "location", "", false); | |||||
| /* Not sure how to export rotation as a 3channel animation, | |||||
| * so separate into 3 single animations for now: | |||||
| */ | |||||
| create_sampled_animation(1, baked_curves[TIME], baked_curves[EULX], ob_name, "rotation", "X", true); | |||||
| create_sampled_animation(1, baked_curves[TIME], baked_curves[EULY], ob_name, "rotation", "Y", true); | |||||
| create_sampled_animation(1, baked_curves[TIME], baked_curves[EULZ], ob_name, "rotation", "Z", true); | |||||
| fprintf(stdout, "Animation Export: Baked %zd frames for %s (sampling rate: %d)\n", | |||||
| baked_curves[0].size(), | |||||
| ob->id.name, | |||||
| this->export_settings->sampling_rate); | |||||
| } | |||||
| /* called for each exported object */ | |||||
| void AnimationExporter::operator()(Object *ob) | |||||
| { | |||||
| char *transformName; | |||||
| /* bool isMatAnim = false; */ /* UNUSED */ | |||||
| //Export transform animations | |||||
| if (ob->adt && ob->adt->action) { | |||||
| 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); | |||||
| } | |||||
| else { | |||||
| if (this->export_settings->sampling_rate == -1) { | |||||
| export_keyframed_animation_set(ob); | |||||
| } | |||||
| else { | |||||
| export_sampled_animation_set(ob); | |||||
| } | |||||
| } | |||||
| } | |||||
| export_object_constraint_animation(ob); | export_object_constraint_animation(ob); | ||||
| //This needs to be handled by extra profiles, so postponed for now | //This needs to be handled by extra profiles, so postponed for now | ||||
| //export_morph_animation(ob); | //export_morph_animation(ob); | ||||
| //Export Lamp parameter animations | //Export Lamp parameter animations | ||||
| if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) { | if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) { | ||||
| fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first); | FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first); | ||||
| while (fcu) { | while (fcu) { | ||||
| transformName = extract_transform_name(fcu->rna_path); | transformName = extract_transform_name(fcu->rna_path); | ||||
| if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) || | if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) || | ||||
| (STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance"))) | (STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance"))) | ||||
| { | { | ||||
| dae_animation(ob, fcu, transformName, true); | create_keyframed_animation(ob, fcu, transformName, true); | ||||
| } | } | ||||
| fcu = fcu->next; | fcu = fcu->next; | ||||
| } | } | ||||
| } | } | ||||
| //Export Camera parameter animations | //Export Camera parameter animations | ||||
| if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) { | if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) { | ||||
| fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first); | FCurve *fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first); | ||||
| while (fcu) { | while (fcu) { | ||||
| transformName = extract_transform_name(fcu->rna_path); | transformName = extract_transform_name(fcu->rna_path); | ||||
| if ((STREQ(transformName, "lens")) || | if ((STREQ(transformName, "lens")) || | ||||
| (STREQ(transformName, "ortho_scale")) || | (STREQ(transformName, "ortho_scale")) || | ||||
| (STREQ(transformName, "clip_end")) || | (STREQ(transformName, "clip_end")) || | ||||
| (STREQ(transformName, "clip_start"))) | (STREQ(transformName, "clip_start"))) | ||||
| { | { | ||||
| dae_animation(ob, fcu, transformName, true); | create_keyframed_animation(ob, fcu, transformName, true); | ||||
| } | } | ||||
| fcu = fcu->next; | fcu = fcu->next; | ||||
| } | } | ||||
| } | } | ||||
| //Export Material parameter animations. | //Export Material parameter animations. | ||||
| for (int a = 0; a < ob->totcol; a++) { | for (int a = 0; a < ob->totcol; a++) { | ||||
| Material *ma = give_current_material(ob, a + 1); | Material *ma = give_current_material(ob, a + 1); | ||||
| if (!ma) continue; | if (!ma) continue; | ||||
| if (ma->adt && ma->adt->action) { | if (ma->adt && ma->adt->action) { | ||||
| /* isMatAnim = true; */ | /* isMatAnim = true; */ | ||||
| fcu = (FCurve *)ma->adt->action->curves.first; | FCurve *fcu = (FCurve *)ma->adt->action->curves.first; | ||||
| while (fcu) { | while (fcu) { | ||||
| transformName = extract_transform_name(fcu->rna_path); | transformName = extract_transform_name(fcu->rna_path); | ||||
| if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) || | if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) || | ||||
| (STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) || | (STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) || | ||||
| (STREQ(transformName, "ior"))) | (STREQ(transformName, "ior"))) | ||||
| { | { | ||||
| dae_animation(ob, fcu, transformName, true, ma); | create_keyframed_animation(ob, fcu, transformName, true, ma); | ||||
| } | } | ||||
| fcu = fcu->next; | fcu = fcu->next; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void AnimationExporter::export_object_constraint_animation(Object *ob) | void AnimationExporter::export_object_constraint_animation(Object *ob) | ||||
| Show All 14 Lines | void AnimationExporter::export_morph_animation(Object *ob) | ||||
| if (!key) return; | if (!key) return; | ||||
| if (key->adt && key->adt->action) { | if (key->adt && key->adt->action) { | ||||
| fcu = (FCurve *)key->adt->action->curves.first; | fcu = (FCurve *)key->adt->action->curves.first; | ||||
| while (fcu) { | while (fcu) { | ||||
| transformName = extract_transform_name(fcu->rna_path); | transformName = extract_transform_name(fcu->rna_path); | ||||
| dae_animation(ob, fcu, transformName, true); | create_keyframed_animation(ob, fcu, transformName, true); | ||||
| fcu = fcu->next; | fcu = fcu->next; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames ) | void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames ) | ||||
| Show All 16 Lines | if (cti && cti->get_constraint_targets) { | ||||
| * - ct->matrix members have not yet been calculated here! | * - ct->matrix members have not yet been calculated here! | ||||
| */ | */ | ||||
| cti->get_constraint_targets(con, &targets); | cti->get_constraint_targets(con, &targets); | ||||
| for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { | for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { | ||||
| obtar = ct->tar; | obtar = ct->tar; | ||||
| if (obtar) | if (obtar) | ||||
| find_frames(obtar, frames); | find_keyframes(obtar, frames); | ||||
| } | } | ||||
| if (cti->flush_constraint_targets) | if (cti->flush_constraint_targets) | ||||
| cti->flush_constraint_targets(con, &targets, 1); | cti->flush_constraint_targets(con, &targets, 1); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| std::string AnimationExporter::getAnimationPathId(const FCurve *fcu) | std::string AnimationExporter::getAnimationPathId(const FCurve *fcu) | ||||
| { | { | ||||
| std::string rna_path = std::string(fcu->rna_path); | std::string rna_path = std::string(fcu->rna_path); | ||||
| return translate_id(rna_path); | return translate_id(rna_path); | ||||
| } | } | ||||
| //convert f-curves to animation curves and write | /* convert f-curves to animation curves and write */ | ||||
| void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma) | void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma) | ||||
| { | { | ||||
| const char *axis_name = NULL; | const char *axis_name = NULL; | ||||
| char anim_id[200]; | char anim_id[200]; | ||||
| bool has_tangents = false; | bool has_tangents = false; | ||||
| bool quatRotation = false; | bool quatRotation = false; | ||||
| Object *obj = NULL; | |||||
| if (STREQ(transformName, "rotation_quaternion") ) { | if (STREQ(transformName, "rotation_quaternion") ) { | ||||
| fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n"); | fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n"); | ||||
| quatRotation = true; | quatRotation = true; | ||||
| return; | return; | ||||
| } | } | ||||
| //axis names for colors | //axis names for colors | ||||
| else if (STREQ(transformName, "color") || | else if (STREQ(transformName, "color") || | ||||
| STREQ(transformName, "specular_color") || | STREQ(transformName, "specular_color") || | ||||
| STREQ(transformName, "diffuse_color") || | STREQ(transformName, "diffuse_color") || | ||||
| STREQ(transformName, "alpha")) | STREQ(transformName, "alpha")) | ||||
| { | { | ||||
| const char *axis_names[] = {"R", "G", "B"}; | const char *axis_names[] = {"R", "G", "B"}; | ||||
| if (fcu->array_index < 3) | if (fcu->array_index < 3) | ||||
| axis_name = axis_names[fcu->array_index]; | axis_name = axis_names[fcu->array_index]; | ||||
| } | } | ||||
| //axis names for transforms | /* | ||||
| else if (STREQ(transformName, "location") || | * Note: Handle transformation animations separately (to apply matrix inverse to fcurves) | ||||
| * We will use the object to evaluate the animation on all keyframes and calculate the | |||||
| * resulting object matrix. We need this to incorporate the | |||||
| * effects of the parent inverse matrix (when it contains a rotation component) | |||||
| * | |||||
| * TODO: try to combine exported fcurves into 3 channel animations like done | |||||
| * in export_sampled_animation(). For now each channel is exported as separate <Animation>. | |||||
| */ | |||||
| else if ( | |||||
| STREQ(transformName, "scale") || | STREQ(transformName, "scale") || | ||||
| STREQ(transformName, "rotation_euler") || | STREQ(transformName, "location") || | ||||
| STREQ(transformName, "rotation_quaternion")) | STREQ(transformName, "rotation_euler")) | ||||
| { | { | ||||
| const char *axis_names[] = {"X", "Y", "Z"}; | const char *axis_names[] = {"X", "Y", "Z"}; | ||||
| if (fcu->array_index < 3) | if (fcu->array_index < 3) { | ||||
| axis_name = axis_names[fcu->array_index]; | axis_name = axis_names[fcu->array_index]; | ||||
| obj = ob; | |||||
| } | |||||
| } | } | ||||
| else { | else { | ||||
| /* no axis name. single parameter */ | /* no axis name. single parameter */ | ||||
| axis_name = ""; | axis_name = ""; | ||||
| } | } | ||||
| std::string ob_name = std::string("null"); | std::string ob_name = std::string("null"); | ||||
| //Create anim Id | /* Create anim Id */ | ||||
| if (ob->type == OB_ARMATURE) { | if (ob->type == OB_ARMATURE) { | ||||
| ob_name = getObjectBoneName(ob, fcu); | ob_name = getObjectBoneName(ob, fcu); | ||||
| BLI_snprintf( | BLI_snprintf( | ||||
| anim_id, | anim_id, | ||||
| sizeof(anim_id), | sizeof(anim_id), | ||||
| "%s_%s.%s", | "%s_%s.%s", | ||||
| (char *)translate_id(ob_name).c_str(), | (char *)translate_id(ob_name).c_str(), | ||||
| (char *)translate_id(transformName).c_str(), | (char *)translate_id(transformName).c_str(), | ||||
| Show All 32 Lines | if (quatRotation) { | ||||
| output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name); | output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name); | ||||
| MEM_freeN(eul); | MEM_freeN(eul); | ||||
| MEM_freeN(eul_axis); | MEM_freeN(eul_axis); | ||||
| } | } | ||||
| else if (STREQ(transformName, "lens") && (ob->type == OB_CAMERA)) { | 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); | output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id); | ||||
| } | } | ||||
| else { | else { | ||||
| output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name); | output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name, obj); | ||||
| } | } | ||||
| // create interpolations source | // create interpolations source | ||||
| std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents); | std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents); | ||||
| // handle tangents (if required) | // handle tangents (if required) | ||||
| std::string intangent_id; | std::string intangent_id; | ||||
| std::string outtangent_id; | std::string outtangent_id; | ||||
| if (has_tangents) { | if (has_tangents) { | ||||
| // create in_tangent source | // create in_tangent source | ||||
| intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name); | intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name, obj); | ||||
| // create out_tangent source | // create out_tangent source | ||||
| outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name); | outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name, obj); | ||||
| } | } | ||||
| std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; | std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; | ||||
| COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); | COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); | ||||
| std::string empty; | std::string empty; | ||||
| sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); | sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); | ||||
| sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); | sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); | ||||
| ▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone) | ||||
| } | } | ||||
| if (!(fcu)) return;*/ | if (!(fcu)) return;*/ | ||||
| bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); | bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); | ||||
| if (!pchan) | if (!pchan) | ||||
| return; | return; | ||||
| //every inserted keyframe of bones. | |||||
| find_frames(ob_arm, fra); | if (this->export_settings->sampling_rate < 1) | ||||
| find_keyframes(ob_arm, fra); | |||||
| else | |||||
| find_sampleframes(ob_arm, fra); | |||||
| if (flag & ARM_RESTPOS) { | if (flag & ARM_RESTPOS) { | ||||
| arm->flag &= ~ARM_RESTPOS; | arm->flag &= ~ARM_RESTPOS; | ||||
| BKE_pose_where_is(scene, ob_arm); | BKE_pose_where_is(scene, ob_arm); | ||||
| } | } | ||||
| if (fra.size()) { | if (fra.size()) { | ||||
| dae_baked_animation(fra, ob_arm, bone); | dae_baked_animation(fra, ob_arm, bone); | ||||
| ▲ Show 20 Lines • Show All 262 Lines • ▼ Show 20 Lines | case COLLADASW::InputSemantic::OUT_TANGENT: | ||||
| } | } | ||||
| break; | break; | ||||
| default: | default: | ||||
| *length = 0; | *length = 0; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| // old function to keep compatibility for calls where offset and object are not needed | |||||
| std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name) | 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); | return create_source_from_fcurve(semantic, fcu, anim_id, axis_name, NULL); | ||||
| } | |||||
| //bool is_angle = STREQ(fcu->rna_path, "rotation"); | void AnimationExporter::evaluate_anim_with_constraints(Object *ob, float ctime) | ||||
| bool is_angle = false; | { | ||||
| BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); | |||||
| ListBase *conlist = get_active_constraints(ob); | |||||
| bConstraint *con; | |||||
| for (con = (bConstraint *)conlist->first; con; con = con->next) { | |||||
| ListBase targets = { NULL, NULL }; | |||||
| if (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path,"spot_size")) is_angle = true; | 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); | |||||
| } | |||||
| /* | |||||
| * ob is needed to aply parent inverse information to fcurve. | |||||
| * TODO: Here we have to step over all keyframes for each object and for each fcurve. | |||||
| * Instead of processing each fcurve one by one, | |||||
| * step over the animation from keyframe to keyframe, | |||||
| * then create adjusted fcurves (and entries) for all affected objects. | |||||
| * Then we would need to step through the scene only once. | |||||
| */ | |||||
| std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob) | |||||
| { | |||||
| std::string source_id = anim_id + get_semantic_suffix(semantic); | |||||
| bool is_angle = (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path, "spot_size")); | |||||
| bool is_euler = strstr(fcu->rna_path, "rotation_euler"); | |||||
| bool is_translation = strstr(fcu->rna_path, "location"); | |||||
| bool is_scale = strstr(fcu->rna_path, "scale"); | |||||
| bool is_tangent = false; | |||||
| int offset_index = 0; | |||||
| COLLADASW::FloatSourceF source(mSW); | COLLADASW::FloatSourceF source(mSW); | ||||
| source.setId(source_id); | source.setId(source_id); | ||||
| source.setArrayId(source_id + ARRAY_ID_SUFFIX); | source.setArrayId(source_id + ARRAY_ID_SUFFIX); | ||||
| source.setAccessorCount(fcu->totvert); | source.setAccessorCount(fcu->totvert); | ||||
| switch (semantic) { | switch (semantic) { | ||||
| case COLLADASW::InputSemantic::INPUT: | case COLLADASW::InputSemantic::INPUT: | ||||
| case COLLADASW::InputSemantic::OUTPUT: | case COLLADASW::InputSemantic::OUTPUT: | ||||
| source.setAccessorStride(1); | source.setAccessorStride(1); | ||||
| offset_index = 0; | |||||
| break; | break; | ||||
| case COLLADASW::InputSemantic::IN_TANGENT: | case COLLADASW::InputSemantic::IN_TANGENT: | ||||
| case COLLADASW::InputSemantic::OUT_TANGENT: | case COLLADASW::InputSemantic::OUT_TANGENT: | ||||
| source.setAccessorStride(2); | source.setAccessorStride(2); | ||||
| offset_index = 1; | |||||
| is_tangent = true; | |||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); | COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); | ||||
| add_source_parameters(param, semantic, is_angle, axis_name, false); | add_source_parameters(param, semantic, is_angle, axis_name, false); | ||||
| source.prepareToAppendValues(); | source.prepareToAppendValues(); | ||||
| for (unsigned int i = 0; i < fcu->totvert; i++) { | for (unsigned int frame_index = 0; frame_index < fcu->totvert; frame_index++) { | ||||
| float fixed_val = 0; | |||||
| if (ob) { | |||||
| float fmat[4][4]; | |||||
| float frame = fcu->bezt[frame_index].vec[1][0]; | |||||
| float ctime = BKE_scene_frame_get_from_ctime(scene, frame); | |||||
| evaluate_anim_with_constraints(ob, ctime); // set object transforms to fcurve's i'th keyframe | |||||
| BKE_object_matrix_local_get(ob, fmat); | |||||
| float floc[3]; | |||||
| float fquat[4]; | |||||
| float fsize[3]; | |||||
| mat4_decompose(floc, fquat, fsize, fmat); | |||||
| if (is_euler) { | |||||
| float eul[3]; | |||||
| quat_to_eul(eul, fquat); | |||||
| fixed_val = RAD2DEGF(eul[fcu->array_index]); | |||||
| } | |||||
| else if (is_translation) { | |||||
| fixed_val = floc[fcu->array_index]; | |||||
| } | |||||
| else if (is_scale) { | |||||
| fixed_val = fsize[fcu->array_index]; | |||||
| } | |||||
| } | |||||
| float values[3]; // be careful! | float values[3]; // be careful! | ||||
| float offset = 0; | |||||
| int length = 0; | int length = 0; | ||||
| get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length); | get_source_values(&fcu->bezt[frame_index], semantic, is_angle, values, &length); | ||||
| for (int j = 0; j < length; j++) | if (is_tangent) { | ||||
| source.appendValues(values[j]); | float bases[3]; | ||||
| int len = 0; | |||||
| get_source_values(&fcu->bezt[frame_index], COLLADASW::InputSemantic::OUTPUT, is_angle, bases, &len); | |||||
| offset = values[offset_index] - bases[0]; | |||||
| } | |||||
| for (int j = 0; j < length; j++) { | |||||
| float val; | |||||
| if (j == offset_index) { | |||||
| if (ob) { | |||||
| val = fixed_val + offset; | |||||
| } | |||||
| else { | |||||
| val = values[j] + offset; | |||||
| } | |||||
| } else { | |||||
| val = values[j]; | |||||
| } | |||||
| source.appendValues(val); | |||||
| } | |||||
| } | } | ||||
| source.finish(); | source.finish(); | ||||
| return source_id; | return source_id; | ||||
| } | } | ||||
| /* | /* | ||||
| Show All 27 Lines | for (unsigned int i = 0; i < fcu->totvert; i++) { | ||||
| } | } | ||||
| } | } | ||||
| source.finish(); | source.finish(); | ||||
| return source_id; | return source_id; | ||||
| } | } | ||||
| /* | |||||
| * only to get OUTPUT source values ( if rotation and hence the axis is also specified ) | |||||
| //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 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); | std::string source_id = anim_id + get_semantic_suffix(semantic); | ||||
| COLLADASW::FloatSourceF source(mSW); | COLLADASW::FloatSourceF source(mSW); | ||||
| source.setId(source_id); | source.setId(source_id); | ||||
| source.setArrayId(source_id + ARRAY_ID_SUFFIX); | source.setArrayId(source_id + ARRAY_ID_SUFFIX); | ||||
| source.setAccessorCount(tot); | source.setAccessorCount(tot); | ||||
| Show All 13 Lines | if (is_rot) | ||||
| val = RAD2DEGF(val); | val = RAD2DEGF(val); | ||||
| source.appendValues(val); | source.appendValues(val); | ||||
| } | } | ||||
| source.finish(); | source.finish(); | ||||
| return source_id; | return source_id; | ||||
| } | } | ||||
| // only used for sources with INPUT semantic | |||||
| /* | |||||
| * 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 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); | std::string source_id = anim_id + get_semantic_suffix(semantic); | ||||
| COLLADASW::FloatSourceF source(mSW); | COLLADASW::FloatSourceF source(mSW); | ||||
| source.setId(source_id); | source.setId(source_id); | ||||
| source.setArrayId(source_id + ARRAY_ID_SUFFIX); | source.setArrayId(source_id + ARRAY_ID_SUFFIX); | ||||
| source.setAccessorCount(fra.size()); | source.setAccessorCount(fra.size()); | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (ob->type == OB_ARMATURE && bone) { | ||||
| enable_fcurves(ob->adt->action, bone->name); | enable_fcurves(ob->adt->action, bone->name); | ||||
| } | } | ||||
| std::vector<float>::iterator it; | std::vector<float>::iterator it; | ||||
| int j = 0; | int j = 0; | ||||
| for (it = frames.begin(); it != frames.end(); it++) { | for (it = frames.begin(); it != frames.end(); it++) { | ||||
| float mat[4][4], ipar[4][4]; | float mat[4][4], ipar[4][4]; | ||||
| float frame = *it; | |||||
| float ctime = BKE_scene_frame_get_from_ctime(scene, *it); | float ctime = BKE_scene_frame_get_from_ctime(scene, frame); | ||||
| CFRA = BKE_scene_frame_get_from_ctime(scene, *it); | CFRA = BKE_scene_frame_get_from_ctime(scene, frame); | ||||
| //BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene,scene->lay); | //BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene,scene->lay); | ||||
| BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); | BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); | ||||
| if (bone) { | if (bone) { | ||||
| if (pchan->flag & POSE_CHAIN) { | if (pchan->flag & POSE_CHAIN) { | ||||
| enable_fcurves(ob->adt->action, NULL); | enable_fcurves(ob->adt->action, NULL); | ||||
| BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); | BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); | ||||
| BKE_pose_where_is(scene, ob); | BKE_pose_where_is(scene, ob); | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); | BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); | ||||
| } | } | ||||
| // compute bone local mat | // compute bone local mat | ||||
| if (bone->parent) { | if (bone->parent) { | ||||
| invert_m4_m4(ipar, parchan->pose_mat); | invert_m4_m4(ipar, parchan->pose_mat); | ||||
| mul_m4_m4m4(mat, ipar, pchan->pose_mat); | mul_m4_m4m4(mat, ipar, pchan->pose_mat); | ||||
| } | } | ||||
| else | else | ||||
| copy_m4_m4(mat, pchan->pose_mat); | copy_m4_m4(mat, pchan->pose_mat); | ||||
| // OPEN_SIM_COMPATIBILITY | /* OPEN_SIM_COMPATIBILITY | ||||
| // AFAIK animation to second life is via BVH, but no | * AFAIK animation to second life is via BVH, but no | ||||
| // reason to not have the collada-animation be correct | * reason to not have the collada-animation be correct | ||||
| */ | |||||
| if (export_settings->open_sim) { | if (export_settings->open_sim) { | ||||
| float temp[4][4]; | float temp[4][4]; | ||||
| copy_m4_m4(temp, bone->arm_mat); | copy_m4_m4(temp, bone->arm_mat); | ||||
| temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; | temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; | ||||
| invert_m4(temp); | invert_m4(temp); | ||||
| mul_m4_m4m4(mat, mat, temp); | mul_m4_m4m4(mat, mat, temp); | ||||
| if (bone->parent) { | if (bone->parent) { | ||||
| copy_m4_m4(temp, bone->parent->arm_mat); | copy_m4_m4(temp, bone->parent->arm_mat); | ||||
| temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; | temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; | ||||
| mul_m4_m4m4(mat, temp, mat); | mul_m4_m4m4(mat, temp, mat); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| calc_ob_mat_at_time(ob, ctime, mat); | BKE_scene_frame_set(scene, ctime); | ||||
| Main *bmain = bc_get_main(); | |||||
| EvaluationContext *ev_context = bc_get_evaluation_context(); | |||||
| BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay); | |||||
| copy_m4_m4(mat, ob->obmat); | |||||
| } | } | ||||
| UnitConverter converter; | UnitConverter converter; | ||||
| double outmat[4][4]; | double outmat[4][4]; | ||||
| converter.mat4_to_dae_double(outmat, mat); | converter.mat4_to_dae_double(outmat, mat); | ||||
| if (this->export_settings->limit_precision) | if (this->export_settings->limit_precision) | ||||
| Show All 11 Lines | std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id) | ||||
| } | } | ||||
| source.finish(); | source.finish(); | ||||
| return source_id; | return source_id; | ||||
| } | } | ||||
| // only used for sources with OUTPUT semantic ( locations and scale) | /* | ||||
| * 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) | std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id) | ||||
| { | { | ||||
| COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; | COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; | ||||
| std::string source_id = anim_id + get_semantic_suffix(semantic); | std::string source_id = anim_id + get_semantic_suffix(semantic); | ||||
| COLLADASW::FloatSourceF source(mSW); | COLLADASW::FloatSourceF source(mSW); | ||||
| source.setId(source_id); | source.setId(source_id); | ||||
| source.setArrayId(source_id + ARRAY_ID_SUFFIX); | source.setArrayId(source_id + ARRAY_ID_SUFFIX); | ||||
| ▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | if (axis_name[0]) | ||||
| return tm_name + "." + std::string(axis_name); | return tm_name + "." + std::string(axis_name); | ||||
| else | else | ||||
| return tm_name; | return tm_name; | ||||
| } | } | ||||
| return std::string(""); | 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 | * 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 AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis) | ||||
| { | { | ||||
| std::string tm_name; | std::string tm_name; | ||||
| bool is_angle = false; | bool is_angle = false; | ||||
| // when given rna_path, determine tm_type from it | // when given rna_path, determine tm_type from it | ||||
| if (rna_path) { | if (rna_path) { | ||||
| char *name = extract_transform_name(rna_path); | char *name = extract_transform_name(rna_path); | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| char *AnimationExporter::extract_transform_name(char *rna_path) | char *AnimationExporter::extract_transform_name(char *rna_path) | ||||
| { | { | ||||
| char *dot = strrchr(rna_path, '.'); | char *dot = strrchr(rna_path, '.'); | ||||
| return dot ? (dot + 1) : 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) | * enable fcurves driving a specific bone, disable all the rest | ||||
| { | * if bone_name = NULL enable all fcurves | ||||
| 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) | void AnimationExporter::enable_fcurves(bAction *act, char *bone_name) | ||||
| { | { | ||||
| FCurve *fcu; | FCurve *fcu; | ||||
| char prefix[200]; | char prefix[200]; | ||||
| if (bone_name) | if (bone_name) | ||||
| BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); | BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | bool AnimationExporter::hasAnimations(Scene *sce) | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| //------------------------------- Not used in the new system.-------------------------------------------------------- | //------------------------------- Not used in the new system.-------------------------------------------------------- | ||||
| void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode) | void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode) | ||||
| { | { | ||||
| if (rotmode > 0) | if (rotmode > 0) | ||||
| find_frames(ob, fra, prefix, "rotation_euler"); | find_keyframes(ob, fra, prefix, "rotation_euler"); | ||||
| else if (rotmode == ROT_MODE_QUAT) | else if (rotmode == ROT_MODE_QUAT) | ||||
| find_frames(ob, fra, prefix, "rotation_quaternion"); | find_keyframes(ob, fra, prefix, "rotation_quaternion"); | ||||
| /*else if (rotmode == ROT_MODE_AXISANGLE) | /*else if (rotmode == ROT_MODE_AXISANGLE) | ||||
| ;*/ | ;*/ | ||||
| } | } | ||||
| void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name) | /* Take care to always have the first frame and the last frame in the animation | ||||
| * regardless of the sampling_rate setting | |||||
| */ | |||||
| void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra) | |||||
| { | |||||
| int frame = scene->r.sfra; | |||||
| do { | |||||
| float ctime = BKE_scene_frame_get_from_ctime(scene, frame); | |||||
| fra.push_back(ctime); | |||||
| if (frame == scene->r.efra) | |||||
| break; | |||||
| frame += this->export_settings->sampling_rate; | |||||
| if (frame > scene->r.efra) | |||||
| frame = scene->r.efra; // make sure the last frame is always exported | |||||
| } while (true); | |||||
| } | |||||
| /* | |||||
| * find keyframes of all the objects animations | |||||
| */ | |||||
| void AnimationExporter::find_keyframes(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()); | |||||
| } | |||||
| } | |||||
| void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name) | |||||
| { | { | ||||
| if (ob->adt && ob->adt->action) { | if (ob->adt && ob->adt->action) { | ||||
| FCurve *fcu = (FCurve *)ob->adt->action->curves.first; | FCurve *fcu = (FCurve *)ob->adt->action->curves.first; | ||||
| for (; fcu; fcu = fcu->next) { | for (; fcu; fcu = fcu->next) { | ||||
| if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix))) | if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix))) | ||||
| continue; | continue; | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type) | ||||
| if (!pchan) | if (!pchan) | ||||
| return; | return; | ||||
| //Fill frame array with key frame values framed at \param:transform_type | //Fill frame array with key frame values framed at \param:transform_type | ||||
| switch (transform_type) { | switch (transform_type) { | ||||
| case 0: | case 0: | ||||
| find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode); | find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode); | ||||
| break; | break; | ||||
| case 1: | case 1: | ||||
| find_frames(ob_arm, fra, prefix, "scale"); | find_keyframes(ob_arm, fra, prefix, "scale"); | ||||
| break; | break; | ||||
| case 2: | case 2: | ||||
| find_frames(ob_arm, fra, prefix, "location"); | find_keyframes(ob_arm, fra, prefix, "location"); | ||||
| break; | break; | ||||
| default: | default: | ||||
| return; | return; | ||||
| } | } | ||||
| // exit rest position | // exit rest position | ||||
| if (flag & ARM_RESTPOS) { | if (flag & ARM_RESTPOS) { | ||||
| arm->flag &= ~ARM_RESTPOS; | arm->flag &= ~ARM_RESTPOS; | ||||
| ▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | bool AnimationExporter::validateConstraints(bConstraint *con) | ||||
| /* these constraints can't be evaluated anyway */ | /* these constraints can't be evaluated anyway */ | ||||
| if (cti->evaluate_constraint == NULL) valid = false; | if (cti->evaluate_constraint == NULL) valid = false; | ||||
| /* influence == 0 should be ignored */ | /* influence == 0 should be ignored */ | ||||
| if (con->enforce == 0.0f) valid = false; | if (con->enforce == 0.0f) valid = false; | ||||
| return valid; | return valid; | ||||
| } | } | ||||
| void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4]) | #if 0 | ||||
| /* | |||||
| * Needed for sampled animations. | |||||
| * This function calculates the object matrix at a given time, | |||||
| * also taking constraints into account. | |||||
| * | |||||
| * XXX: Why looking at the constraints here is necessary? | |||||
| * Maybe this can be done better? | |||||
| */ | |||||
| void AnimationExporter::calc_obmat_at_time(Object *ob, float ctime ) | |||||
| { | { | ||||
| BKE_scene_frame_set(scene, ctime); | |||||
| Main *bmain = bc_get_main(); | |||||
| EvaluationContext *ev_context = bc_get_evaluation_context(); | |||||
| BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay); | |||||
| ListBase *conlist = get_active_constraints(ob); | ListBase *conlist = get_active_constraints(ob); | ||||
| bConstraint *con; | bConstraint *con; | ||||
| for (con = (bConstraint *)conlist->first; con; con = con->next) { | for (con = (bConstraint *)conlist->first; con; con = con->next) { | ||||
| ListBase targets = {NULL, NULL}; | ListBase targets = {NULL, NULL}; | ||||
| const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); | const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); | ||||
| if (cti && cti->get_constraint_targets) { | if (cti && cti->get_constraint_targets) { | ||||
| Show All 9 Lines | if (cti && cti->get_constraint_targets) { | ||||
| } | } | ||||
| } | } | ||||
| if (cti->flush_constraint_targets) | if (cti->flush_constraint_targets) | ||||
| cti->flush_constraint_targets(con, &targets, 1); | cti->flush_constraint_targets(con, &targets, 1); | ||||
| } | } | ||||
| } | } | ||||
| BKE_object_where_is_calc_time(scene, ob, ctime); | BKE_object_where_is_calc_time(scene, ob, ctime); | ||||
| copy_m4_m4(mat, ob->obmat); | |||||
| } | } | ||||
| #endif | |||||