Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py60
-rw-r--r--source/blender/editors/animation/keyframes_draw.c19
-rw-r--r--source/blender/editors/armature/armature_intern.h2
-rw-r--r--source/blender/editors/armature/armature_ops.c2
-rw-r--r--source/blender/editors/armature/poseSlide.c347
-rw-r--r--source/blender/editors/armature/poseobject.c3
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h3
7 files changed, 411 insertions, 25 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 31704173258..bbeb76d2cb1 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -177,10 +177,6 @@ class VIEW3D_MT_transform(bpy.types.Menu):
layout.operator("object.origin_set", text="Origin to Geometry").type = 'ORIGIN_GEOMETRY'
layout.operator("object.origin_set", text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR'
- if context.mode == 'OBJECT':
- layout.operator("object.align")
- layout.operator("object.randomize_transform")
-
class VIEW3D_MT_mirror(bpy.types.Menu):
bl_label = "Mirror"
@@ -254,14 +250,6 @@ class VIEW3D_MT_uv_map(bpy.types.Menu):
layout.operator("uv.reset")
- layout.separator()
-
- # python scripts
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("uv.smart_project")
- layout.operator("uv.lightmap_pack")
- layout.operator("uv.follow_active_quads")
-
# ********** View menus **********
@@ -1172,23 +1160,23 @@ class VIEW3D_MT_pose(bpy.types.Menu):
layout.separator()
layout.menu("VIEW3D_MT_transform")
- layout.menu("VIEW3D_MT_snap")
layout.menu("VIEW3D_MT_pose_transform")
+ layout.menu("VIEW3D_MT_pose_apply")
+
+ layout.menu("VIEW3D_MT_snap")
layout.separator()
+ # TODO: make this an "Animation" menu like we have for object?
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframe...")
layout.operator("anim.keying_set_active_set", text="Change Keying Set...")
layout.separator()
- layout.operator("pose.relax")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_pose_apply")
+ layout.menu("VIEW3D_MT_pose_slide")
+ layout.menu("VIEW3D_MT_pose_propagate")
layout.separator()
@@ -1198,7 +1186,7 @@ class VIEW3D_MT_pose(bpy.types.Menu):
layout.separator()
- layout.menu("VIEW3D_MT_pose_pose")
+ layout.menu("VIEW3D_MT_pose_library")
layout.menu("VIEW3D_MT_pose_motion")
layout.menu("VIEW3D_MT_pose_group")
@@ -1246,7 +1234,28 @@ class VIEW3D_MT_pose_transform(bpy.types.Menu):
layout.label(text="Origin")
-class VIEW3D_MT_pose_pose(bpy.types.Menu):
+class VIEW3D_MT_pose_slide(bpy.types.Menu):
+ bl_label = "In-Betweens"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("pose.push")
+ layout.operator("pose.relax")
+ layout.operator("pose.breakdown")
+
+
+class VIEW3D_MT_pose_propagate(bpy.types.Menu):
+ bl_label = "Propagate"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("pose.propagate")
+ layout.operator("pose.propagate", text="To Next Keyframe").mode = 'NEXT_KEY'
+
+
+class VIEW3D_MT_pose_library(bpy.types.Menu):
bl_label = "Pose Library"
def draw(self, context):
@@ -2313,3 +2322,14 @@ class VIEW3D_PT_context_properties(bpy.types.Panel):
if member:
# Draw with no edit button
rna_prop_ui.draw(self.layout, context, member, object, False)
+
+
+def register():
+ bpy.utils.register_module(__name__)
+
+
+def unregister():
+ bpy.utils.unregister_module(__name__)
+
+if __name__ == "__main__":
+ register()
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index aab38790687..3f8f8dc1e84 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -80,7 +80,7 @@
/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-// NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes
+/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
short compare_ak_cfraPtr (void *node, void *data)
{
ActKeyColumn *ak= (ActKeyColumn *)node;
@@ -311,6 +311,23 @@ static BezTriple *abk_get_bezt_with_value (ActBeztColumn *abk, float value)
/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
+/* Comparator callback used for ActKeyBlock and cframe float-value pointer */
+/* NOTE: this is exported to other modules that use the ActKeyBlocks for finding long-keyframes */
+short compare_ab_cfraPtr (void *node, void *data)
+{
+ ActKeyBlock *ab= (ActKeyBlock *)node;
+ float *cframe= data;
+
+ if (*cframe < ab->start)
+ return -1;
+ else if (*cframe > ab->start)
+ return 1;
+ else
+ return 0;
+}
+
+/* --------------- */
+
/* Create a ActKeyColumn for a pair of BezTriples */
static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
{
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index b72cf75d9c7..7a6141540bd 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -200,6 +200,8 @@ void POSE_OT_push(struct wmOperatorType *ot);
void POSE_OT_relax(struct wmOperatorType *ot);
void POSE_OT_breakdown(struct wmOperatorType *ot);
+void POSE_OT_propagate(struct wmOperatorType *ot);
+
/* ******************************************************* */
/* editarmature.c */
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index 34942a2edc1..545cff82483 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -146,6 +146,8 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_armature_layers);
WM_operatortype_append(POSE_OT_bone_layers);
+ WM_operatortype_append(POSE_OT_propagate);
+
/* POSELIB */
WM_operatortype_append(POSELIB_OT_browse_interactive);
WM_operatortype_append(POSELIB_OT_apply_pose);
diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c
index 39d65a4526f..680cd4b6430 100644
--- a/source/blender/editors/armature/poseSlide.c
+++ b/source/blender/editors/armature/poseSlide.c
@@ -61,8 +61,6 @@
#include "WM_api.h"
#include "WM_types.h"
-
-
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_screen.h"
@@ -77,7 +75,13 @@
* for interactively controlling the spacing of poses, but also
* for 'pushing' and/or 'relaxing' extremes as they see fit.
*
- * B) Pose Sculpting
+ * B) Propagate
+ * This tool copies elements of the selected pose to successive
+ * keyframes, allowing the animator to go back and modify the poses
+ * for some "static" pose controls, without having to repeatedly
+ * doing a "next paste" dance.
+ *
+ * C) Pose Sculpting
* This is yet to be implemented, but the idea here is to use
* sculpting techniques to make it easier to pose rigs by allowing
* rigs to be manipulated using a familiar paint-based interface.
@@ -854,3 +858,340 @@ void POSE_OT_breakdown (wmOperatorType *ot)
}
/* **************************************************** */
+/* B) Pose Propagate */
+
+/* "termination conditions" - i.e. when we stop */
+typedef enum ePosePropagate_Termination {
+ /* stop when we run out of keyframes */
+ POSE_PROPAGATE_LAST_KEY = 0,
+ /* stop after the next keyframe */
+ POSE_PROPAGATE_NEXT_KEY,
+ /* stop after the specified frame */
+ POSE_PROPAGATE_BEFORE_FRAME,
+ /* stop after */
+ POSE_PROPAGATE_SMART_HOLDS
+} ePosePropagate_Termination;
+
+/* --------------------------------- */
+
+/* helper for pose_propagate_get_boneHoldEndFrame()
+ * Checks if ActKeyBlock should exist...
+ */
+// TODO: move to keyframes drawing API...
+static short actkeyblock_is_valid (ActKeyBlock *ab, DLRBT_Tree *keys)
+{
+ ActKeyColumn *ak;
+ short startCurves, endCurves, totCurves;
+
+ /* check that block is valid */
+ if (ab == NULL)
+ return 0;
+
+ /* find out how many curves occur at each keyframe */
+ ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->start);
+ startCurves = (ak)? ak->totcurve: 0;
+
+ ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->end);
+ endCurves = (ak)? ak->totcurve: 0;
+
+ /* only draw keyblock if it appears in at all of the keyframes at lowest end */
+ if (!startCurves && !endCurves)
+ return 0;
+
+ totCurves = (startCurves>endCurves)? endCurves: startCurves;
+ return (ab->totcurve >= totCurves);
+}
+
+/* get frame on which the "hold" for the bone ends
+ * XXX: this may not really work that well if a bone moves on some channels and not others
+ * if this happens to be a major issue, scrap this, and just make this happen
+ * independently per F-Curve
+ */
+static float pose_propagate_get_boneHoldEndFrame (Object *ob, tPChanFCurveLink *pfl, float startFrame)
+{
+ DLRBT_Tree keys, blocks;
+ ActKeyBlock *ab;
+
+ AnimData *adt= ob->adt;
+ LinkData *ld;
+ float endFrame = startFrame;
+
+ /* set up optimised data-structures for searching for relevant keyframes + holds */
+ BLI_dlrbTree_init(&keys);
+ BLI_dlrbTree_init(&blocks);
+
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ fcurve_to_keylist(adt, fcu, &keys, &blocks);
+ }
+
+ BLI_dlrbTree_linkedlist_sync(&keys);
+ BLI_dlrbTree_linkedlist_sync(&blocks);
+
+ /* find the long keyframe (i.e. hold), and hence obtain the endFrame value
+ * - the best case would be one that starts on the frame itself
+ */
+ ab = (ActKeyBlock *)BLI_dlrbTree_search_exact(&blocks, compare_ab_cfraPtr, &startFrame);
+
+ if (actkeyblock_is_valid(ab, &keys) == 0) {
+ /* There are only two cases for no-exact match:
+ * 1) the current frame is just before another key but not on a key itself
+ * 2) the current frame is on a key, but that key doesn't link to the next
+ *
+ * If we've got the first case, then we can search for another block,
+ * otherwise forget it, as we'd be overwriting some valid data.
+ */
+ if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &startFrame) == NULL) {
+ /* we've got case 1, so try the one after */
+ ab = (ActKeyBlock *)BLI_dlrbTree_search_next(&blocks, compare_ab_cfraPtr, &startFrame);
+
+ if (actkeyblock_is_valid(ab, &keys) == 0) {
+ /* try the block before this frame then as last resort */
+ ab = (ActKeyBlock *)BLI_dlrbTree_search_prev(&blocks, compare_ab_cfraPtr, &startFrame);
+
+ /* whatever happens, stop searching now... */
+ if (actkeyblock_is_valid(ab, &keys) == 0) {
+ /* restrict range to just the frame itself
+ * i.e. everything is in motion, so no holds to safely overwrite
+ */
+ ab = NULL;
+ }
+ }
+ }
+ else {
+ /* we've got case 2 - set ab to NULL just in case, since we shouldn't do anything in this case */
+ ab = NULL;
+ }
+ }
+
+ /* check if we can go any further than we've already gone */
+ if (ab) {
+ /* go to next if it is also valid and meets "extension" criteria */
+ while (ab->next) {
+ ActKeyBlock *abn = (ActKeyBlock *)ab->next;
+
+ /* must be valid */
+ if (actkeyblock_is_valid(abn, &keys) == 0)
+ break;
+ /* should start on the same frame that the last ended on */
+ if (ab->end != abn->start)
+ break;
+ /* should have the same number of curves */
+ if (ab->totcurve != abn->totcurve)
+ break;
+ /* should have the same value
+ * XXX: this may be a bit fuzzy on larger data sets, so be careful
+ */
+ if (ab->val != abn->val)
+ break;
+
+ /* we can extend the bounds to the end of this "next" block now */
+ ab = abn;
+ }
+
+ /* end frame can now take the value of the end of the block */
+ endFrame = ab->end;
+ }
+
+ /* free temp memory */
+ BLI_dlrbTree_free(&keys);
+ BLI_dlrbTree_free(&blocks);
+
+ /* return the end frame we've found */
+ return endFrame;
+}
+
+/* get reference value from F-Curve using RNA */
+static float pose_propagate_get_refVal (Object *ob, FCurve *fcu)
+{
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ float value;
+
+ /* base pointer is always the object -> id_ptr */
+ RNA_id_pointer_create(&ob->id, &id_ptr);
+
+ /* resolve the property... */
+ if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) {
+ if (RNA_property_array_check(&ptr, prop)) {
+ /* array */
+ if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value= (float)RNA_property_boolean_get_index(&ptr, prop, fcu->array_index);
+ break;
+ case PROP_INT:
+ value= (float)RNA_property_int_get_index(&ptr, prop, fcu->array_index);
+ break;
+ case PROP_FLOAT:
+ value= RNA_property_float_get_index(&ptr, prop, fcu->array_index);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else {
+ /* not an array */
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value= (float)RNA_property_boolean_get(&ptr, prop);
+ break;
+ case PROP_INT:
+ value= (float)RNA_property_int_get(&ptr, prop);
+ break;
+ case PROP_ENUM:
+ value= (float)RNA_property_enum_get(&ptr, prop);
+ break;
+ case PROP_FLOAT:
+ value= RNA_property_float_get(&ptr, prop);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return value;
+}
+
+/* propagate just works along each F-Curve in turn */
+static void pose_propagate_fcurve (wmOperator *op, Object *ob, tPChanFCurveLink *pfl, FCurve *fcu, float startFrame, float endFrame)
+{
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ BezTriple *bezt;
+ float refVal = 0.0f;
+ short keyExists;
+ int i, match;
+ short first=1;
+
+ /* skip if no keyframes to edit */
+ if ((fcu->bezt == NULL) || (fcu->totvert < 2))
+ return;
+
+ /* find the reference value from bones directly, which means that the user
+ * doesn't need to firstly keyframe the pose (though this doesn't mean that
+ * they can't either)
+ */
+ refVal = pose_propagate_get_refVal(ob, fcu);
+
+ /* find the first keyframe to start propagating from
+ * - if there's a keyframe on the current frame, we probably want to save this value there too
+ * since it may be as of yet unkeyed
+ * - if starting before the starting frame, don't touch the key, as it may have had some valid
+ * values
+ */
+ match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
+
+ if (fcu->bezt[match].vec[1][0] < startFrame)
+ i = match + 1;
+ else
+ i = match;
+
+ for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
+ /* additional termination conditions based on the operator 'mode' property go here... */
+ if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
+ /* stop if keyframe is outside the accepted range */
+ if (bezt->vec[1][0] > endFrame)
+ break;
+ }
+ else if (mode == POSE_PROPAGATE_NEXT_KEY) {
+ /* stop after the first keyframe has been processed */
+ if (first == 0)
+ break;
+ }
+
+ /* just flatten handles, since values will now be the same either side... */
+ // TODO: perhaps a fade-out modulation of the value is required here (optional once again)?
+ bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
+
+ /* select keyframe to indicate that it's been changed */
+ bezt->f2 |= SELECT;
+ first = 0;
+ }
+}
+
+/* --------------------------------- */
+
+static int pose_propagate_exec (bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob= ED_object_pose_armature(CTX_data_active_object(C));
+ bAction *act= (ob && ob->adt)? ob->adt->action : NULL;
+
+ ListBase pflinks = {NULL, NULL};
+ tPChanFCurveLink *pfl;
+
+ float endFrame = RNA_float_get(op->ptr, "end_frame");
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* sanity checks */
+ if (ob == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No object to propagate poses for");
+ return OPERATOR_CANCELLED;
+ }
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* isolate F-Curves related to the selected bones */
+ poseAnim_mapping_get(C, &pflinks, ob, act);
+
+ /* for each bone, perform the copying required */
+ for (pfl = pflinks.first; pfl; pfl = pfl->next) {
+ LinkData *ld;
+
+ /* mode-specific data preprocessing (requiring access to all curves) */
+ if (mode == POSE_PROPAGATE_SMART_HOLDS) {
+ /* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
+ * from the keyframe that occurs after the current frame
+ */
+ endFrame = pose_propagate_get_boneHoldEndFrame(ob, pfl, (float)CFRA);
+ }
+
+ /* go through propagating pose to keyframes, curve by curve */
+ for (ld = pfl->fcurves.first; ld; ld= ld->next)
+ pose_propagate_fcurve(op, ob, pfl, (FCurve *)ld->data, (float)CFRA, endFrame);
+ }
+
+ /* free temp data */
+ poseAnim_mapping_free(&pflinks);
+
+ /* updates + notifiers */
+ poseAnim_mapping_refresh(C, scene, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* --------------------------------- */
+
+void POSE_OT_propagate (wmOperatorType *ot)
+{
+ static EnumPropertyItem terminate_items[]= {
+ {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "Last Keyframe", ""},
+ {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "Next Keyframe", ""},
+ {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", "Propagate pose to all keyframes between current frame and 'Frame' property"},
+ {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", "Propagate pose to all keyframes after current frame that don't change (Default behaviour)"},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Propagate Pose";
+ ot->idname= "POSE_OT_propagate";
+ ot->description= "Copy selected aspects of the current pose to subsequent poses already keyframed";
+
+ /* callbacks */
+ ot->exec= pose_propagate_exec;
+ ot->poll= ED_operator_posemode; // XXX: needs selected bones!
+
+ /* flag */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ // TODO: add "fade out" control for tapering off amount of propagation as time goes by?
+ ot->prop= RNA_def_enum(ot->srna, "mode", terminate_items, POSE_PROPAGATE_SMART_HOLDS, "Terminate Mode", "Method used to determine when to stop propagating pose to keyframes");
+ RNA_def_float(ot->srna, "end_frame", 250.0, FLT_MIN, FLT_MAX, "End Frame", "Frame to stop propagating frames to", 1.0, 250.0);
+}
+
+/* **************************************************** */
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
index 23253c0b4cf..e9892c62a68 100644
--- a/source/blender/editors/armature/poseobject.c
+++ b/source/blender/editors/armature/poseobject.c
@@ -57,6 +57,7 @@
#include "BKE_constraint.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_modifier.h"
#include "BKE_report.h"
@@ -1600,7 +1601,7 @@ static int pose_autoside_names_exec (bContext *C, wmOperator *op)
void POSE_OT_autoside_names (wmOperatorType *ot)
{
static EnumPropertyItem axis_items[]= {
- {0, "XAXIS", 0, "X-Axis", "Left/Right"},
+ {0, "XAXIS", 0, "X-Axis", "Left/Right"},
{1, "YAXIS", 0, "Y-Axis", "Front/Back"},
{2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
{0, NULL, 0, NULL, NULL}};
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index c697f8cc435..544c5c4a1ef 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -146,5 +146,8 @@ void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_
/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
short compare_ak_cfraPtr(void *node, void *data);
+/* Comparator callback used for ActKeyBlocks and cframe float-value pointer */
+short compare_ab_cfraPtr(void *node, void *data);
+
#endif /* ED_KEYFRAMES_DRAW_H */