/* * ***** 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 "AnimationCurveCache.h" extern "C" { #include "BKE_action.h" #include "BLI_listbase.h" } AnimationCurveCache::AnimationCurveCache(bContext *C): mContext(C) { } AnimationCurveCache::~AnimationCurveCache() { clear_cache(); } void AnimationCurveCache::clear_cache() { } void AnimationCurveCache::clear_cache(Object *ob) { } void AnimationCurveCache::create_curves(Object *ob) { } void AnimationCurveCache::addObject(Object *ob) { cached_objects.push_back(ob); } bool AnimationCurveCache::bone_matrix_local_get(Object *ob, Bone *bone, float(&mat)[4][4], bool for_opensim) { /* Ok, lets be super cautious and check if the bone exists */ bPose *pose = ob->pose; bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name); if (!pchan) { return false; } bAction *action = bc_getSceneObjectAction(ob); bPoseChannel *parchan = pchan->parent; enable_fcurves(action, bone->name); float ipar[4][4]; 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 (for_opensim) { 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); } } return true; } void AnimationCurveCache::sampleMain(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim) { std::map>::iterator frame; for (frame = sample_frames.begin(); frame != sample_frames.end(); frame++) { int frame_index = frame->first; std::vector sample_points = frame->second; bc_update_scene(mContext, scene, frame_index); for (int spi = 0; spi < sample_points.size(); spi++) { SamplePoint &point = sample_points[spi]; Object *ob = point.get_object(); float mat[4][4]; if (ob->type == OB_ARMATURE) { /* For Armatures we need to check if this maybe is a pose sample point*/ Bone *bone = point.get_bone(); if (bone) { if (bone_matrix_local_get(ob, bone, mat, for_opensim)) { point.set_matrix(mat); } continue; } } /* When this SamplePoint is not for a Bone, * then we just store the Object local matrix here */ BKE_object_matrix_local_get(ob, mat); point.set_matrix(mat); } } } /* * enable fcurves driving a specific bone, disable all the rest * if bone_name = NULL enable all fcurves */ void AnimationCurveCache::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; } } } /* * Sample the scene at frames where object fcurves * have defined keys. */ void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim, bool keyframe_at_end) { create_sample_frames_from_keyframes(); sampleMain(scene, atm_type, for_opensim); } void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, int sampling_rate, bool for_opensim, bool keyframe_at_end) { create_sample_frames_generated(scene->r.sfra, scene->r.efra, sampling_rate, keyframe_at_end); sampleMain(scene, atm_type, for_opensim); } std::vector *AnimationCurveCache::getSampledCurves(Object *ob) { std::map>::iterator fcurves; fcurves = cached_curves.find(ob); return (fcurves == cached_curves.end()) ? NULL : &fcurves->second; } std::vector &AnimationCurveCache::getFrameInfos(int frame_index) { std::map>::iterator frames = sample_frames.find(frame_index); if (frames == sample_frames.end()) { std::vector sample_points; sample_frames[frame_index] = sample_points; } return sample_frames[frame_index]; } void AnimationCurveCache::add_sample_point(SamplePoint &point) { int frame_index = point.get_frame(); std::vector &frame_infos = getFrameInfos(frame_index); frame_infos.push_back(point); } /* * loop over all cached objects * loop over all fcurves * record all keyframes * * The vector sample_frames finally contains a list of vectors * where each vector contains a list of SamplePoints which * need to be processed when evaluating the animation. */ void AnimationCurveCache::create_sample_frames_from_keyframes() { sample_frames.clear(); for (int i = 0; i < cached_objects.size(); i++) { Object *ob = cached_objects[i]; bAction *action = bc_getSceneObjectAction(ob); FCurve *fcu = (FCurve *)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]; int frame_index = int(f); SamplePoint sample_point(frame_index, ob, fcu, i); add_sample_point(sample_point); } } } } /* * loop over all cached objects * loop over active action using a stesize of sampling_rate * record all frames * * The vector sample_frames finally contains a list of vectors * where each vector contains a list of SamplePoints which * need to be processed when evaluating the animation. * Note: The FCurves of the objects will not be used here. */ void AnimationCurveCache::create_sample_frames_generated(float sfra, float efra, int sampling_rate, int keyframe_at_end) { sample_frames.clear(); for (int i = 0; i < cached_objects.size(); i++) { Object *ob = cached_objects[i]; float f = sfra; do { int frame_index = int(f); SamplePoint sample_point(frame_index, ob); add_sample_point(sample_point); /* Depending on the Object type add more sample points here */ if (ob && ob->type == OB_ARMATURE) { LISTBASE_FOREACH(bPoseChannel *, pchan, &ob->pose->chanbase) { SamplePoint point(frame_index, ob, pchan->bone); add_sample_point(sample_point); } } if (f == efra) break; f += sampling_rate; if (f > efra) if (keyframe_at_end) f = efra; // make sure the last frame is always exported else break; } while (true); } } Matrix::Matrix() { unit_m4(matrix); } Matrix::Matrix(float (&mat)[4][4]) { set_matrix(mat); } void Matrix::set_matrix(float(&mat)[4][4]) { copy_m4_m4(matrix, mat); } void Matrix::set_matrix(Matrix &mat) { copy_m4_m4(matrix, mat.matrix); } void Matrix::get_matrix(float(&mat)[4][4]) { copy_m4_m4(mat, matrix); } SamplePoint::SamplePoint(int frame, Object *ob) { this->frame = frame; this->fcu = NULL; this->ob = ob; this->pose_bone = NULL; this->index = -1; } SamplePoint::SamplePoint(int frame, Object *ob, FCurve *fcu, int index) { this->frame = frame; this->fcu = fcu; this->ob = ob; this->pose_bone = NULL; this->index = index; this->path = std::string(fcu->rna_path); /* Further elaborate on what this Fcurve is doing by checking * its rna_path */ if (ob && ob->type == OB_ARMATURE) { char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); bPose *pose = ob->pose; if (boneName) { bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName); this->pose_bone = pchan->bone; } } } SamplePoint::SamplePoint(int frame, Object *ob, Bone *bone) { this->frame = frame; this->fcu = NULL; this->ob = ob; this->pose_bone = bone; this->index = -1; this->path = "pose.bones[\"" + id_name(bone) + "\"].matrix"; } Matrix &SamplePoint::get_matrix() { return matrix; } void SamplePoint::set_matrix(Matrix &mat) { this->matrix.set_matrix(mat); } void SamplePoint::set_matrix(float(&mat)[4][4]) { } Object *SamplePoint::get_object() { return this->ob; } Bone *SamplePoint::get_bone() { return this->pose_bone; } FCurve *SamplePoint::get_fcurve() { return this->fcu; } int SamplePoint::get_frame() { return this->frame; } int SamplePoint::get_fcurve_index() { return this->index; } std::string &SamplePoint::get_path() { return path; }