diff options
-rw-r--r-- | release/scripts/ui/properties_animviz.py | 160 | ||||
-rw-r--r-- | release/scripts/ui/properties_data_armature.py | 50 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_anim.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/anim.c | 62 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 8 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 17 | ||||
-rw-r--r-- | source/blender/editors/armature/poseobject.c | 230 | ||||
-rw-r--r-- | source/blender/editors/include/ED_object.h | 4 | ||||
-rw-r--r-- | source/blender/editors/object/object_edit.c | 112 | ||||
-rw-r--r-- | source/blender/editors/object/object_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/object/object_ops.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawanimviz.c | 3 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawarmature.c | 195 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 16 |
14 files changed, 389 insertions, 476 deletions
diff --git a/release/scripts/ui/properties_animviz.py b/release/scripts/ui/properties_animviz.py new file mode 100644 index 00000000000..2085030a29c --- /dev/null +++ b/release/scripts/ui/properties_animviz.py @@ -0,0 +1,160 @@ +# ##### 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import bpy + +narrowui = 180 + +################################################ +# Generic Panels (Independent of DataType) + +class MotionPathButtonsPanel(bpy.types.Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_label = "Motion Paths" + + def draw_settings(self, context, avs, wide_ui, bones=False): + layout = self.layout + + mps = avs.motion_paths + + if wide_ui: + layout.prop(mps, "type", expand=True) + else: + layout.prop(mps, "type", text="") + + split = layout.split() + + col = split.column() + sub = col.column(align=True) + if (mps.type == 'CURRENT_FRAME'): + sub.prop(mps, "before_current", text="Before") + sub.prop(mps, "after_current", text="After") + elif (mps.type == 'RANGE'): + sub.prop(mps, "start_frame", text="Start") + sub.prop(mps, "end_frame", text="End") + + sub.prop(mps, "frame_step", text="Step") + if bones: + col.row().prop(mps, "bake_location", expand=True) + + if wide_ui: + col = split.column() + col.label(text="Display:") + col.prop(mps, "show_frame_numbers", text="Frame Numbers") + col.prop(mps, "highlight_keyframes", text="Keyframes") + col.prop(mps, "show_keyframe_numbers", text="Keyframe Numbers") + +# FIXME: this panel still needs to be ported so that it will work correctly with animviz +class OnionSkinButtonsPanel(bpy.types.Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_label = "Onion Skinning" + + def draw(self, context): + layout = self.layout + + arm = context.armature + wide_ui = context.region.width > narrowui + + if wide_ui: + layout.prop(arm, "ghost_type", expand=True) + else: + layout.prop(arm, "ghost_type", text="") + + split = layout.split() + + col = split.column() + + sub = col.column(align=True) + if arm.ghost_type == 'RANGE': + sub.prop(arm, "ghost_start_frame", text="Start") + sub.prop(arm, "ghost_end_frame", text="End") + sub.prop(arm, "ghost_size", text="Step") + elif arm.ghost_type == 'CURRENT_FRAME': + sub.prop(arm, "ghost_step", text="Range") + sub.prop(arm, "ghost_size", text="Step") + + if wide_ui: + col = split.column() + col.label(text="Display:") + col.prop(arm, "ghost_only_selected", text="Selected Only") + +################################################ +# Specific Panels for DataTypes + +class OBJECT_PT_motion_paths(MotionPathButtonsPanel): + #bl_label = "Object Motion Paths" + bl_context = "object" + + def poll(self, context): + return (context.object) + + def draw(self, context): + layout = self.layout + + ob = context.object + wide_ui = context.region.width > narrowui + + self.draw_settings(context, ob.animation_visualisation, wide_ui) + + layout.separator() + + split = layout.split() + + col = split.column() + col.operator("object.paths_calculate", text="Calculate Paths") + + if wide_ui: + col = split.column() + col.operator("object.paths_clear", text="Clear Paths") + +class DATA_PT_motion_paths(MotionPathButtonsPanel): + #bl_label = "Bone Motion Paths" + bl_context = "data" + + def poll(self, context): + # XXX: include posemode check? + return (context.object) and (context.armature) + + def draw(self, context): + layout = self.layout + + ob = context.object + wide_ui = context.region.width > narrowui + + self.draw_settings(context, ob.pose.animation_visualisation, wide_ui, bones=True) + + layout.separator() + + split = layout.split() + + col = split.column() + col.operator("pose.paths_calculate", text="Calculate Paths") + + if wide_ui: + col = split.column() + col.operator("pose.paths_clear", text="Clear Paths") + + + +#bpy.types.register(OBJECT_PT_onion_skinning) +#bpy.types.register(DATA_PT_onion_skinning) +bpy.types.register(OBJECT_PT_motion_paths) +bpy.types.register(DATA_PT_motion_paths) diff --git a/release/scripts/ui/properties_data_armature.py b/release/scripts/ui/properties_data_armature.py index bded38ee3cc..0b33825279b 100644 --- a/release/scripts/ui/properties_data_armature.py +++ b/release/scripts/ui/properties_data_armature.py @@ -162,54 +162,7 @@ class DATA_PT_bone_groups(DataButtonsPanel): #row.operator("object.bone_group_select", text="Select") #row.operator("object.bone_group_deselect", text="Deselect") - -class DATA_PT_paths(DataButtonsPanel): - bl_label = "Paths" - - def draw(self, context): - layout = self.layout - - arm = context.armature - wide_ui = context.region.width > narrowui - - if wide_ui: - layout.prop(arm, "paths_type", expand=True) - else: - layout.prop(arm, "paths_type", text="") - - split = layout.split() - - col = split.column() - sub = col.column(align=True) - if (arm.paths_type == 'CURRENT_FRAME'): - sub.prop(arm, "path_before_current", text="Before") - sub.prop(arm, "path_after_current", text="After") - elif (arm.paths_type == 'RANGE'): - sub.prop(arm, "path_start_frame", text="Start") - sub.prop(arm, "path_end_frame", text="End") - - sub.prop(arm, "path_size", text="Step") - col.row().prop(arm, "paths_location", expand=True) - - if wide_ui: - col = split.column() - col.label(text="Display:") - col.prop(arm, "paths_show_frame_numbers", text="Frame Numbers") - col.prop(arm, "paths_highlight_keyframes", text="Keyframes") - col.prop(arm, "paths_show_keyframe_numbers", text="Keyframe Numbers") - - layout.separator() - - split = layout.split() - - col = split.column() - col.operator("pose.paths_calculate", text="Calculate Paths") - - if wide_ui: - col = split.column() - col.operator("pose.paths_clear", text="Clear Paths") - - +# TODO: this panel will soon be depreceated too class DATA_PT_ghost(DataButtonsPanel): bl_label = "Ghost" @@ -302,7 +255,6 @@ bpy.types.register(DATA_PT_context_arm) bpy.types.register(DATA_PT_skeleton) bpy.types.register(DATA_PT_display) bpy.types.register(DATA_PT_bone_groups) -bpy.types.register(DATA_PT_paths) bpy.types.register(DATA_PT_ghost) bpy.types.register(DATA_PT_iksolver_itasc) diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 4862f4e5c46..c664469527e 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -53,7 +53,9 @@ void animviz_free_motionpath_cache(struct bMotionPath *mpath); void animviz_free_motionpath(struct bMotionPath *mpath); struct bMotionPath *animviz_verify_motionpaths(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan); -void animviz_calc_motionpaths(struct Scene *scene, struct Object *ob); + +void animviz_get_object_motionpaths(Object *ob, ListBase *targets); +void animviz_calc_motionpaths(struct Scene *scene, ListBase *targets); /* ---------------------------------------------------- */ /* Curve Paths */ diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 507fc520a85..6d95df3ca84 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -154,7 +154,7 @@ void animviz_free_motionpath(bMotionPath *mpath) /* ------------------- */ -/* Setup motion paths for the given data +/* Setup motion paths for the given data * - scene: current scene (for frame ranges, etc.) * - ob: object to add paths for (must be provided) * - pchan: posechannel to add paths for (optional; if not provided, object-paths are assumed) @@ -226,8 +226,10 @@ typedef struct MPathTarget { /* ........ */ -/* get list of motion paths to be baked (assumes the list is ready to be used) */ -static void motionpaths_get_bake_targets(Object *ob, ListBase *targets) +/* get list of motion paths to be baked for the given object + * - assumes the given list is ready to be used + */ +void animviz_get_object_motionpaths(Object *ob, ListBase *targets) { MPathTarget *mpt; @@ -260,6 +262,8 @@ static void motionpaths_get_bake_targets(Object *ob, ListBase *targets) } } +/* ........ */ + /* perform baking for the targets on the current frame */ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets) { @@ -270,8 +274,10 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets) bMotionPath *mpath= mpt->mpath; bMotionPathVert *mpv; - /* current frame must be within the range the cache works for */ - if (IN_RANGE(CFRA, mpath->start_frame, mpath->end_frame) == 0) + /* current frame must be within the range the cache works for + * - is inclusive of the first frame, but not the last otherwise we get buffer overruns + */ + if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame)) continue; /* get the relevant cache vert to write to */ @@ -297,36 +303,30 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets) } } -/* ........ */ - /* Perform baking of the given object's and/or its bones' transforms to motion paths * - scene: current scene * - ob: object whose flagged motionpaths should get calculated * - recalc: whether we need to */ // TODO: include reports pointer? -void animviz_calc_motionpaths(Scene *scene, Object *ob) +void animviz_calc_motionpaths(Scene *scene, ListBase *targets) { - ListBase targets = {NULL, NULL}; MPathTarget *mpt; int sfra, efra; int cfra; - /* sanity checks */ - if (ob == NULL) - return; - - /* get motion paths to affect */ - motionpaths_get_bake_targets(ob, &targets); - - if (targets.first == NULL) + /* sanity check */ + if (ELEM(NULL, targets, targets->first)) return; /* set frame values */ cfra = CFRA; sfra = efra = cfra; - for (mpt= targets.first; mpt; mpt= mpt->next) { + // TODO: this method could be improved... + // 1) max range for standard baking + // 2) minimum range for recalc baking (i.e. between keyfames, but how?) + for (mpt= targets->first; mpt; mpt= mpt->next) { /* try to increase area to do (only as much as needed) */ sfra= MIN2(sfra, mpt->mpath->start_frame); efra= MAX2(efra, mpt->mpath->end_frame); @@ -340,23 +340,29 @@ void animviz_calc_motionpaths(Scene *scene, Object *ob) * that doesn't force complete update, but for now, this is the * most accurate way! */ - scene_update_for_newframe(scene, ob->lay); // XXX is the layer flag too restrictive? + scene_update_for_newframe(scene, scene->lay); // XXX this is the best way we can get anything moving /* perform baking for targets */ - motionpaths_calc_bake_targets(scene, &targets); + motionpaths_calc_bake_targets(scene, targets); } /* reset original environment */ CFRA= cfra; - scene_update_for_newframe(scene, ob->lay); // XXX is the layer flag too restrictive? - - // TODO: make an API call for this too? - ob->avs.recalc &= ~ANIMVIZ_RECALC_PATHS; - if (ob->pose) - ob->pose->avs.recalc &= ~ANIMVIZ_RECALC_PATHS; + scene_update_for_newframe(scene, scene->lay); // XXX this is the best way we can get anything moving - /* free temp data */ - BLI_freelistN(&targets); + /* clear recalc flags from targets */ + for (mpt= targets->first; mpt; mpt= mpt->next) { + bAnimVizSettings *avs; + + /* get pointer to animviz settings for each target */ + if (mpt->pchan) + avs= &mpt->ob->pose->avs; + else + avs= &mpt->ob->avs; + + /* clear the flag requesting recalculation of targets */ + avs->recalc &= ~ANIMVIZ_RECALC_PATHS; + } } /* ******************************************************************** */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index e4079eac31b..3a7d79b8e00 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1602,7 +1602,13 @@ void armature_rebuild_pose(Object *ob, bArmature *arm) int counter=0; /* only done here */ - if(ob->pose==NULL) ob->pose= MEM_callocN(sizeof(bPose), "new pose"); + if(ob->pose==NULL) { + /* create new pose */ + ob->pose= MEM_callocN(sizeof(bPose), "new pose"); + + /* set default settings for animviz */ + animviz_settings_init(&ob->pose->avs); + } pose= ob->pose; /* clear */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8975dcd4c67..96b2b793267 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -10381,9 +10381,16 @@ static void do_versions(FileData *fd, Library *lib, Main *main) avs->ghost_sf= arm->ghostsf; avs->ghost_ef= arm->ghostef; + if ((avs->ghost_sf == avs->ghost_ef) && (avs->ghost_sf == 0)) { + avs->ghost_sf= 1; + avs->ghost_ef= 100; + } /* type */ - avs->ghost_type= arm->ghosttype; + if (arm->ghostep == 0) + avs->ghost_type= GHOST_TYPE_NONE; + else + avs->ghost_type= arm->ghosttype + 1; /* stepsize */ avs->ghost_step= arm->ghostsize; @@ -10394,9 +10401,15 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* ranges */ avs->path_bc= arm->pathbc; avs->path_ac= arm->pathac; + if ((avs->path_bc == avs->path_ac) && (avs->path_bc == 0)) + avs->path_bc= avs->path_ac= 10; avs->path_sf= arm->pathsf; avs->path_ef= arm->pathef; + if ((avs->path_sf == avs->path_ef) && (avs->path_sf == 0)) { + avs->path_sf= 1; + avs->path_ef= 250; + } /* flags */ if (arm->pathflag & ARM_PATH_FNUMS) @@ -10419,6 +10432,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) if (avs->path_step == 0) avs->path_step= 1; } + else + animviz_settings_init(&ob->pose->avs); } } diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index d26238150ca..ee6e87292fa 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -51,6 +51,7 @@ #include "DNA_view3d_types.h" #include "DNA_userdef_types.h" +#include "BKE_anim.h" #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" @@ -200,6 +201,7 @@ int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan) } /* ********************************************** */ +/* Motion Paths */ /* For the object with pose/action: update paths for those that have got them * This should selectively update paths that exist... @@ -208,120 +210,25 @@ int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan) */ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob) { - bArmature *arm; - bPoseChannel *pchan; - Base *base; - float *fp; - int cfra; - int sfra, efra; - - /* sanity checks */ - if ELEM(NULL, ob, ob->pose) - return; - arm= ob->data; - - /* set frame values */ - cfra = CFRA; - sfra = efra = cfra; - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if ((pchan->bone) && (arm->layer & pchan->bone->layer)) { - if (pchan->path) { - /* if the pathsf and pathef aren't initialised, abort! */ - // XXX can now have negative frames, so this check needs improvement - if (ELEM(0, pchan->pathsf, pchan->pathef)) - return; - - /* try to increase area to do (only as much as needed) */ - sfra= MIN2(sfra, pchan->pathsf); - efra= MAX2(efra, pchan->pathef); - } - } - } - if (efra <= sfra) return; - - /* hack: for unsaved files, set OB_RECALC so that paths can get calculated */ - if ((ob->recalc & OB_RECALC)==0) { - ob->recalc |= OB_RECALC; - DAG_id_update_flags(&ob->id); - } - else - DAG_id_update_flags(&ob->id); - - /* calculate path over requested range */ - for (CFRA=sfra; CFRA<=efra; CFRA++) { - /* do all updates */ - for (base= FIRSTBASE; base; base= base->next) { - if (base->object->recalc) { - int temp= base->object->recalc; - - if (base->object->adt) - BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL); - - /* update object */ - object_handle_update(scene, base->object); - base->object->recalc= temp; - } - } - - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if ((pchan->bone) && (arm->layer & pchan->bone->layer)) { - if (pchan->path) { - /* only update if: - * - in range of this pchan's existing path - * - ... insert evil filtering/optimising conditions here... - */ - if (IN_RANGE(CFRA, pchan->pathsf, pchan->pathef)) { - fp= pchan->path+3*(CFRA-sfra); - - if (arm->pathflag & ARM_PATH_HEADS) { - VECCOPY(fp, pchan->pose_head); - } - else { - VECCOPY(fp, pchan->pose_tail); - } - - mul_m4_v3(ob->obmat, fp); - } - } - } - } - } + ListBase targets = {NULL, NULL}; - /* reset flags */ - CFRA= cfra; - ob->pose->flag &= ~POSE_RECALCPATHS; + /* set flag to force recalc, then grab the relevant bones to target */ + ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS; + animviz_get_object_motionpaths(ob, &targets); - /* flush one final time - to restore to the original state */ - for (base= FIRSTBASE; base; base= base->next) { - if (base->object->recalc) { - int temp= base->object->recalc; - - if (base->object->adt) - BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL); - - object_handle_update(scene, base->object); - base->object->recalc= temp; - } - } + /* recalculate paths, then free */ + animviz_calc_motionpaths(scene, &targets); + BLI_freelistN(&targets); } -/* --------- */ - /* For the object with pose/action: create path curves for selected bones * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range */ static int pose_calculate_paths_exec (bContext *C, wmOperator *op) { - wmWindow *win= CTX_wm_window(C); ScrArea *sa= CTX_wm_area(C); Scene *scene= CTX_data_scene(C); Object *ob; - bArmature *arm; - bPoseChannel *pchan; - Base *base; - float *fp; - int cfra; - int sfra, efra; /* since this call may also be used from the buttons window, we need to check for where to get the object */ if (sa->spacetype == SPACE_BUTS) @@ -329,109 +236,20 @@ static int pose_calculate_paths_exec (bContext *C, wmOperator *op) else ob= CTX_data_active_object(C); - /* only continue if there's an object */ - if ELEM(NULL, ob, ob->pose) - return OPERATOR_CANCELLED; - arm= ob->data; - - /* version patch for older files here (do_versions patch too complicated) */ - if ((arm->pathsf == 0) || (arm->pathef == 0)) { - arm->pathsf = SFRA; - arm->pathef = EFRA; - } - if (arm->pathsize == 0) { - arm->pathsize = 1; - } - - /* get frame values to use */ - cfra= CFRA; - sfra = arm->pathsf; - efra = arm->pathef; - - if (efra <= sfra) { - BKE_report(op->reports, RPT_ERROR, "Can't calculate paths when pathlen <= 0"); + if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; - } - /* hack: for unsaved files, set OB_RECALC so that paths can get calculated */ - if ((ob->recalc & OB_RECALC)==0) { - ob->recalc |= OB_RECALC; - DAG_id_update_flags(&ob->id); - } - else - DAG_id_update_flags(&ob->id); - - /* alloc the path cache arrays */ - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) { - if (arm->layer & pchan->bone->layer) { - pchan->pathlen= efra-sfra+1; - pchan->pathsf= sfra; - pchan->pathef= efra+1; - if (pchan->path) - MEM_freeN(pchan->path); - pchan->path= MEM_callocN(3*pchan->pathlen*sizeof(float), "pchan path"); - } - } - } - - /* step through frame range sampling the values */ - for (CFRA=sfra; CFRA<=efra; CFRA++) { - /* for each frame we calculate, update time-cursor... (may be too slow) */ - WM_timecursor(win, CFRA); - - /* do all updates */ - for (base= FIRSTBASE; base; base= base->next) { - if (base->object->recalc) { - int temp= base->object->recalc; - - if (base->object->adt) - BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL); - - object_handle_update(scene, base->object); - base->object->recalc= temp; - } - } - - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) { - if (arm->layer & pchan->bone->layer) { - if (pchan->path) { - fp= pchan->path+3*(CFRA-sfra); - - if (arm->pathflag & ARM_PATH_HEADS) { - VECCOPY(fp, pchan->pose_head); - } - else { - VECCOPY(fp, pchan->pose_tail); - } - - mul_m4_v3(ob->obmat, fp); - } - } - } - } + /* set up path data for bones being calculated */ + CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) + { + /* verify makes sure that the selected bone has a bone with the appropriate settings */ + animviz_verify_motionpaths(scene, ob, pchan); } + CTX_DATA_END; - /* restore original cursor */ - WM_cursor_restore(win); - - /* reset current frame, and clear flags */ - CFRA= cfra; - ob->pose->flag &= ~POSE_RECALCPATHS; - - /* flush one final time - to restore to the original state */ - for (base= FIRSTBASE; base; base= base->next) { - if (base->object->recalc) { - int temp= base->object->recalc; - - if (base->object->adt) - BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL); - - object_handle_update(scene, base->object); - base->object->recalc= temp; - } - } + /* calculate the bones that now have motionpaths... */ + // TODO: only make for the selected bones? + ED_pose_recalculate_paths(C, scene, ob); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); @@ -464,12 +282,12 @@ void ED_pose_clear_paths(Object *ob) if ELEM(NULL, ob, ob->pose) return; - /* free the path blocks */ + /* free the motionpath blocks */ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) { - if (pchan->path) { - MEM_freeN(pchan->path); - pchan->path= NULL; + if (pchan->mpath) { + animviz_free_motionpath(pchan->mpath); + pchan->mpath= NULL; } } } @@ -491,7 +309,7 @@ static int pose_clear_paths_exec (bContext *C, wmOperator *op) if ELEM(NULL, ob, ob->pose) return OPERATOR_CANCELLED; - /* for now, just call the API function for this (which is shared with backend functions) */ + /* use the backend function for this */ ED_pose_clear_paths(ob); /* notifiers for updates */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 91b297b7581..aa6914ab0ad 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -95,6 +95,10 @@ void ED_object_single_users(struct Scene *scene, int full); int object_is_libdata(struct Object *ob); int object_data_is_libdata(struct Object *ob); +/* object motion paths */ +void ED_objects_clear_paths(struct bContext *C, struct Scene *scene); +void ED_objects_recalculate_paths(struct bContext *C, struct Scene *scene); + /* constraints */ struct ListBase *get_active_constraints(struct Object *ob); struct ListBase *get_constraint_lb(struct Object *ob, struct bConstraint *con, struct bPoseChannel **pchan_r); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 54fa3f51eb6..e2d714fac0d 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1610,6 +1610,118 @@ void copy_attr_menu(Scene *scene, View3D *v3d) copy_attr(scene, v3d, event); } +/* ********************************************** */ +/* Motion Paths */ + +/* For the object with pose/action: update paths for those that have got them + * This should selectively update paths that exist... + * + * To be called from various tools that do incremental updates + */ +void ED_objects_recalculate_paths(bContext *C, Scene *scene) +{ + ListBase targets = {NULL, NULL}; + + /* loop over objects in scene */ + CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) + { + /* set flag to force recalc, then grab the relevant bones to target */ + ob->avs.recalc |= ANIMVIZ_RECALC_PATHS; + animviz_get_object_motionpaths(ob, &targets); + } + CTX_DATA_END; + + /* recalculate paths, then free */ + animviz_calc_motionpaths(scene, &targets); + BLI_freelistN(&targets); +} + +/* For the object with pose/action: create path curves for selected bones + * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range + */ +static int object_calculate_paths_exec (bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + + /* set up path data for bones being calculated */ + CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) + { + /* verify makes sure that the selected bone has a bone with the appropriate settings */ + animviz_verify_motionpaths(scene, ob, NULL); + } + CTX_DATA_END; + + /* calculate the bones that now have motionpaths... */ + // TODO: only make for the selected bones? + ED_objects_recalculate_paths(C, scene); + + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_paths_calculate (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Calculate Object Paths"; + ot->idname= "OBJECT_OT_paths_calculate"; + ot->description= "Calculate paths for the selected bones."; + + /* api callbacks */ + ot->exec= object_calculate_paths_exec; + ot->poll= ED_operator_object_active_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* --------- */ + +/* for the object with pose/action: clear path curves for selected bones only */ +void ED_objects_clear_paths(bContext *C, Scene *scene) +{ + /* loop over objects in scene */ + CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) + { + if (ob->mpath) { + animviz_free_motionpath(ob->mpath); + ob->mpath= NULL; + } + } + CTX_DATA_END; +} + +/* operator callback for this */ +static int object_clear_paths_exec (bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + + /* use the backend function for this */ + ED_objects_clear_paths(C, scene); + + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_paths_clear (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Clear Object Paths"; + ot->idname= "OBJECT_OT_paths_clear"; + ot->description= "Clear path caches for selected bones."; + + /* api callbacks */ + ot->exec= object_clear_paths_exec; + ot->poll= ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; +} + + /********************** Smooth/Flat *********************/ static int shade_smooth_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index cfb4cda2460..a11ead1fe9d 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -79,6 +79,8 @@ void OBJECT_OT_restrictview_clear(struct wmOperatorType *ot); void OBJECT_OT_proxy_make(struct wmOperatorType *ot); void OBJECT_OT_shade_smooth(struct wmOperatorType *ot); void OBJECT_OT_shade_flat(struct wmOperatorType *ot); +void OBJECT_OT_paths_calculate(struct wmOperatorType *ot); +void OBJECT_OT_paths_clear(struct wmOperatorType *ot); /* object_select.c */ void OBJECT_OT_select_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 8b29e2ca2ae..80992887e97 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -81,6 +81,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_restrictview_set); WM_operatortype_append(OBJECT_OT_shade_smooth); WM_operatortype_append(OBJECT_OT_shade_flat); + WM_operatortype_append(OBJECT_OT_paths_calculate); + WM_operatortype_append(OBJECT_OT_paths_clear); WM_operatortype_append(OBJECT_OT_parent_set); WM_operatortype_append(OBJECT_OT_parent_no_inverse_set); diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index b8184a60cee..c57fad96a94 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -104,6 +104,7 @@ void draw_motion_paths_init(Scene *scene, View3D *v3d, ARegion *ar) * - assumes that the viewport has already been initialised properly * i.e. draw_motion_paths_init() has been called */ +// FIXME: the text is still drawn in the wrong space - it includes the current transforms of the object still... void draw_motion_path_instance(Scene *scene, View3D *v3d, ARegion *ar, Object *ob, bPoseChannel *pchan, bAnimVizSettings *avs, bMotionPath *mpath) { @@ -273,7 +274,7 @@ void draw_motion_path_instance(Scene *scene, View3D *v3d, ARegion *ar, glPointSize(1.0f); /* Draw frame numbers of keyframes */ - if (avs->path_viewflag & (MOTIONPATH_VIEW_FNUMS|MOTIONPATH_VIEW_KFNOS)) { + if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) { for (i=0, mpv=mpv_start; i < len; i++, mpv++) { float mframe= (float)(sfra + i); diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index c59c5cddb3f..bfdeaef1834 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -2118,200 +2118,21 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) */ static void draw_pose_paths(Scene *scene, View3D *v3d, ARegion *ar, Object *ob) { - RegionView3D *rv3d= ar->regiondata; - AnimData *adt= BKE_animdata_from_id(&ob->id); + bAnimVizSettings *avs= &ob->pose->avs; bArmature *arm= ob->data; bPoseChannel *pchan; - ActKeyColumn *ak; - DLRBT_Tree keys; - float *fp, *fp_start; - int a, stepsize; - int sfra, efra, len; - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - - /* version patch here - cannot access frame info from file reading */ - if (arm->pathsize == 0) arm->pathsize= 1; - stepsize = arm->pathsize; + /* setup drawing environment for paths */ + draw_motion_paths_init(scene, v3d, ar); + /* draw paths where they exist and they releated bone is visible */ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if (pchan->bone->layer & arm->layer) { - if (pchan->path) { - /* version patch here - cannot access frame info from file reading */ - if ((pchan->pathsf == 0) || (pchan->pathef == 0)) { - pchan->pathsf= SFRA; - pchan->pathef= EFRA; - } - - /* get frame ranges */ - if (arm->pathflag & ARM_PATH_ACFRA) { - int sind; - - /* With "Around Current", we only choose frames from around - * the current frame to draw. However, this range is still - * restricted by the limits of the original path. - */ - sfra= CFRA - arm->pathbc; - efra= CFRA + arm->pathac; - if (sfra < pchan->pathsf) sfra= pchan->pathsf; - if (efra > pchan->pathef) efra= pchan->pathef; - - len= efra - sfra; - - sind= sfra - pchan->pathsf; - fp_start= (pchan->path + (3*sind)); - } - else { - sfra= pchan->pathsf; - efra = sfra + pchan->pathlen; - len = pchan->pathlen; - fp_start = pchan->path; - } - - /* draw curve-line of path */ - glShadeModel(GL_SMOOTH); - - glBegin(GL_LINE_STRIP); - for (a=0, fp=fp_start; a<len; a++, fp+=3) { - float intensity; /* how faint */ - - /* set color - * - more intense for active/selected bones, less intense for unselected bones - * - black for before current frame, green for current frame, blue for after current frame - * - intensity decreases as distance from current frame increases - */ - #define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max-min)) + min) - if ((a+sfra) < CFRA) { - /* black - before cfra */ - if (pchan->bone->flag & BONE_SELECTED) { - // intensity= 0.5f; - intensity = SET_INTENSITY(sfra, a, CFRA, 0.25f, 0.75f); - } - else { - //intensity= 0.8f; - intensity = SET_INTENSITY(sfra, a, CFRA, 0.68f, 0.92f); - } - UI_ThemeColorBlend(TH_WIRE, TH_BACK, intensity); - } - else if ((a+sfra) > CFRA) { - /* blue - after cfra */ - if (pchan->bone->flag & BONE_SELECTED) { - //intensity = 0.5f; - intensity = SET_INTENSITY(CFRA, a, efra, 0.25f, 0.75f); - } - else { - //intensity = 0.8f; - intensity = SET_INTENSITY(CFRA, a, efra, 0.68f, 0.92f); - } - UI_ThemeColorBlend(TH_BONE_POSE, TH_BACK, intensity); - } - else { - /* green - on cfra */ - if (pchan->bone->flag & BONE_SELECTED) { - intensity= 0.5f; - } - else { - intensity= 0.99f; - } - UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); - } - - /* draw a vertex with this color */ - glVertex3fv(fp); - } - - glEnd(); - glShadeModel(GL_FLAT); - - glPointSize(1.0); - - /* draw little black point at each frame - * NOTE: this is not really visible/noticable - */ - glBegin(GL_POINTS); - for (a=0, fp=fp_start; a<len; a++, fp+=3) - glVertex3fv(fp); - glEnd(); - - /* Draw little white dots at each framestep value */ - UI_ThemeColor(TH_TEXT_HI); - glBegin(GL_POINTS); - for (a=0, fp=fp_start; a<len; a+=stepsize, fp+=(stepsize*3)) - glVertex3fv(fp); - glEnd(); - - /* Draw frame numbers at each framestep value */ - if (arm->pathflag & ARM_PATH_FNUMS) { - for (a=0, fp=fp_start; a<len; a+=stepsize, fp+=(stepsize*3)) { - char str[32]; - - /* only draw framenum if several consecutive highlighted points don't occur on same point */ - if (a == 0) { - sprintf(str, "%d", (a+sfra)); - view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); - } - else if ((a > stepsize) && (a < len-stepsize)) { - if ((equals_v3v3(fp, fp-(stepsize*3))==0) || (equals_v3v3(fp, fp+(stepsize*3))==0)) { - sprintf(str, "%d", (a+sfra)); - view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); - } - } - } - } - - /* Keyframes - dots and numbers */ - if (arm->pathflag & ARM_PATH_KFRAS) { - /* build list of all keyframes in active action for pchan */ - BLI_dlrbTree_init(&keys); - - if (adt) { - bActionGroup *agrp= action_groups_find_named(adt->action, pchan->name); - if (agrp) { - agroup_to_keylist(adt, agrp, &keys, NULL); - BLI_dlrbTree_linkedlist_sync(&keys); - } - } - - /* Draw slightly-larger yellow dots at each keyframe */ - UI_ThemeColor(TH_VERTEX_SELECT); - glPointSize(5.0f); - - glBegin(GL_POINTS); - for (a=0, fp=fp_start; a<len; a++, fp+=3) { - for (ak= keys.first; ak; ak= ak->next) { - if (ak->cfra == (a+sfra)) - glVertex3fv(fp); - } - } - glEnd(); - - glPointSize(1.0f); - - /* Draw frame numbers of keyframes */ - if ((arm->pathflag & ARM_PATH_FNUMS) || (arm->pathflag & ARM_PATH_KFNOS)) { - for(a=0, fp=fp_start; a<len; a++, fp+=3) { - for (ak= keys.first; ak; ak= ak->next) { - if (ak->cfra == (a+sfra)) { - char str[32]; - - sprintf(str, "%d", (a+sfra)); - view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); - } - } - } - } - - BLI_dlrbTree_free(&keys); - } - } - } + if ((pchan->bone->layer & arm->layer) && (pchan->mpath)) + draw_motion_path_instance(scene, v3d, ar, ob, pchan, avs, pchan->mpath); } - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - glPopMatrix(); + /* cleanup after drawing */ + draw_motion_paths_cleanup(scene, v3d, ar); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c3e248c9d7c..b10b74ff160 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -5180,6 +5180,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) /* no return after this point, otherwise leaks */ view3d_cached_text_draw_begin(); + /* draw keys? */ #if 0 // XXX old animation system @@ -5260,8 +5261,19 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) /* patch? children objects with a timeoffs change the parents. How to solve! */ /* if( ((int)ob->ctime) != F_(scene->r.cfra)) where_is_object(scene, ob); */ - /* draw paths... */ - // TODO... + /* draw motion paths (in view space) */ + if (ob->mpath) { + bAnimVizSettings *avs= &ob->avs; + + /* setup drawing environment for paths */ + draw_motion_paths_init(scene, v3d, ar); + + /* draw motion path for object */ + draw_motion_path_instance(scene, v3d, ar, ob, NULL, avs, ob->mpath); + + /* cleanup after drawing */ + draw_motion_paths_cleanup(scene, v3d, ar); + } /* multiply view with object matrix. * local viewmat and persmat, to calculate projections */ |