diff options
Diffstat (limited to 'source/blender/editors/armature')
26 files changed, 1063 insertions, 10092 deletions
diff --git a/source/blender/editors/armature/BIF_generate.h b/source/blender/editors/armature/BIF_generate.h deleted file mode 100644 index e229b0f342a..00000000000 --- a/source/blender/editors/armature/BIF_generate.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * ***** 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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/armature/BIF_generate.h - * \ingroup edarmature - */ - - -#ifndef __BIF_GENERATE_H__ -#define __BIF_GENERATE_H__ - -struct ToolSettings; -struct EditBone; -struct BArcIterator; -struct bArmature; -struct ListBase; - -typedef int (NextSubdivisionFunc)(struct ToolSettings *, struct BArcIterator *, int, int, float[3], float[3]); - -float calcArcCorrelation(struct BArcIterator *iter, int start, int end, float v0[3], float n[3]); - -int nextFixedSubdivision(struct ToolSettings *toolsettings, struct BArcIterator *iter, int start, int end, float head[3], float p[3]); -int nextLengthSubdivision(struct ToolSettings *toolsettings, struct BArcIterator *iter, int start, int end, float head[3], float p[3]); -int nextAdaptativeSubdivision(struct ToolSettings *toolsettings, struct BArcIterator *iter, int start, int end, float head[3], float p[3]); - -struct EditBone *subdivideArcBy(struct ToolSettings *toolsettings, struct bArmature *arm, ListBase *editbones, struct BArcIterator *iter, - float invmat[4][4], float tmat[3][3], NextSubdivisionFunc next_subdividion); - -void setBoneRollFromNormal(struct EditBone *bone, const float no[3], float invmat[4][4], float tmat[3][3]); - - -#endif /* __BIF_GENERATE_H__ */ diff --git a/source/blender/editors/armature/BIF_retarget.h b/source/blender/editors/armature/BIF_retarget.h deleted file mode 100644 index 2bd2b80190b..00000000000 --- a/source/blender/editors/armature/BIF_retarget.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * ***** 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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/armature/BIF_retarget.h - * \ingroup edarmature - */ - -#ifndef __BIF_RETARGET_H__ -#define __BIF_RETARGET_H__ - -#include "DNA_listBase.h" - -#include "BLI_graph.h" -#include "BLI_ghash.h" -#include "BLI_task.h" -#include "BLI_threads.h" - -#include "reeb.h" - -struct Object; -struct bArmature; -struct bContext; - -struct EditBone; - -struct RigGraph; -struct RigNode; -struct RigArc; -struct RigEdge; - -#define USE_THREADS - -typedef struct RigGraph { - ListBase arcs; - ListBase nodes; - - float length; - - FreeArc free_arc; - FreeNode free_node; - RadialSymmetry radial_symmetry; - AxialSymmetry axial_symmetry; - /*********************************/ - - int flag; - - ListBase controls; - ListBase *editbones; - - struct RigNode *head; - ReebGraph *link_mesh; - - - TaskScheduler *task_scheduler; - TaskPool *task_pool; - - GHash *bones_map; /* map of editbones by name */ - GHash *controls_map; /* map of rigcontrols by bone pointer */ - - struct Object *ob; -} RigGraph; - -typedef struct RigNode { - void *next, *prev; - float p[3]; - int flag; - - int degree; - struct BArc **arcs; - - int subgraph_index; - - int symmetry_level; - int symmetry_flag; - float symmetry_axis[3]; - /*********************************/ - - ReebNode *link_mesh; -} RigNode; - -typedef struct RigArc { - void *next, *prev; - RigNode *head, *tail; - int flag; - - float length; - - int symmetry_level; - int symmetry_group; - int symmetry_flag; - /*********************************/ - - ListBase edges; - int count; - ReebArc *link_mesh; -} RigArc; - -typedef struct RigEdge { - struct RigEdge *next, *prev; - float head[3], tail[3]; - float length; - float angle; /* angle to next edge */ - float up_angle; /* angle between up_axis and the joint normal (defined as Previous edge CrossProduct Current edge */ - struct EditBone *bone; - float up_axis[3]; -} RigEdge; - -/* Graph flags */ -#define RIG_FREE_BONELIST 1 - -/* Control flags */ -#define RIG_CTRL_HEAD_DONE 1 -#define RIG_CTRL_TAIL_DONE 2 -#define RIG_CTRL_PARENT_DEFORM 4 -#define RIG_CTRL_FIT_ROOT 8 -#define RIG_CTRL_FIT_BONE 16 - -#define RIG_CTRL_DONE (RIG_CTRL_HEAD_DONE | RIG_CTRL_TAIL_DONE) - -/* Control tail flags */ -typedef enum { - TL_NONE = 0, - TL_TAIL, - TL_HEAD -} LinkTailMode; - -typedef struct RigControl { - struct RigControl *next, *prev; - float head[3], tail[3]; - struct EditBone *bone; - struct EditBone *link; - struct EditBone *link_tail; - float up_axis[3]; - float offset[3]; - float qrot[4]; /* for dual linked bones, store the rotation of the linked bone for the finalization */ - int flag; - LinkTailMode tail_mode; -} RigControl; - -void BIF_retargetArc(struct bContext *C, ReebArc *earc, RigGraph *template_rigg); -RigGraph *RIG_graphFromArmature(const struct bContext *C, struct Object *ob, struct bArmature *arm); -int RIG_nbJoints(RigGraph *rg); -const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index); -void RIG_freeRigGraph(BGraph *rg); - -/* UNUSED */ -void BIF_retargetArmature(bContext *C); -void BIF_adjustRetarget(bContext *C); -/* UNUSED / print funcs */ -void RIG_printArc(struct RigGraph *rg, struct RigArc *arc); -void RIG_printGraph(struct RigGraph *rg); -void RIG_printArcBones(struct RigArc *arc); - -#endif /* __BIF_RETARGET_H__ */ diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 4c394d7836a..96467ee2c2a 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -23,10 +23,12 @@ set(INC ../../blenkernel ../../blenlib ../../blentranslation + ../../depsgraph ../../gpu ../../makesdna ../../makesrna ../../windowmanager + ../../../../intern/clog ../../../../intern/guardedalloc ../../../../intern/eigen ../../../../intern/glew-mx @@ -45,9 +47,6 @@ set(SRC armature_select.c armature_skinning.c armature_utils.c - editarmature_generate.c - editarmature_retarget.c - editarmature_sketch.c editarmature_undo.c meshlaplacian.c pose_edit.c @@ -57,13 +56,9 @@ set(SRC pose_slide.c pose_transform.c pose_utils.c - reeb.c - BIF_generate.h - BIF_retarget.h armature_intern.h meshlaplacian.h - reeb.h ) if(WITH_INTERNATIONAL) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index b268baf0f97..c1fb1dcf82f 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -126,7 +126,6 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) bArmature *arm; EditBone *ebone, *newbone, *flipbone; float mat[3][3], imat[3][3]; - const float *curs; int a, to_root = 0; Object *obedit; Scene *scene; @@ -188,8 +187,8 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) newbone->flag |= BONE_CONNECTED; } - curs = ED_view3d_cursor3d_get(scene, v3d); - copy_v3_v3(newbone->tail, curs); + const View3DCursor *curs = ED_view3d_cursor3d_get(scene, v3d); + copy_v3_v3(newbone->tail, curs->location); sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]); if (a == 1) @@ -221,26 +220,26 @@ static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEv Scene *scene; ARegion *ar; View3D *v3d; - float *fp, tvec[3], oldcurs[3], mval_f[2]; + float tvec[3], oldcurs[3], mval_f[2]; int retv; scene = CTX_data_scene(C); ar = CTX_wm_region(C); v3d = CTX_wm_view3d(C); - fp = ED_view3d_cursor3d_get(scene, v3d); + View3DCursor *cursor = ED_view3d_cursor3d_get(scene, v3d); - copy_v3_v3(oldcurs, fp); + copy_v3_v3(oldcurs, cursor->location); VECCOPY2D(mval_f, event->mval); - ED_view3d_win_to_3d(v3d, ar, fp, mval_f, tvec); - copy_v3_v3(fp, tvec); + ED_view3d_win_to_3d(v3d, ar, cursor->location, mval_f, tvec); + copy_v3_v3(cursor->location, tvec); /* extrude to the where new cursor is and store the operation result */ retv = armature_click_extrude_exec(C, op); /* restore previous 3d cursor position */ - copy_v3_v3(fp, oldcurs); + copy_v3_v3(cursor->location, oldcurs); return retv; } @@ -829,7 +828,7 @@ static int armature_extrude_exec(bContext *C, wmOperator *op) { Object *obedit; bArmature *arm; - EditBone *newbone, *ebone, *flipbone, *first = NULL; + EditBone *newbone = NULL, *ebone, *flipbone, *first = NULL; int a, totbone = 0, do_extrude; bool forked = RNA_boolean_get(op->ptr, "forked"); @@ -1013,7 +1012,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "name", name); - copy_v3_v3(curs, ED_view3d_cursor3d_get(CTX_data_scene(C), CTX_wm_view3d(C))); + copy_v3_v3(curs, ED_view3d_cursor3d_get(CTX_data_scene(C), CTX_wm_view3d(C))->location); /* Get inverse point for head and orientation for tail */ invert_m4_m4(obedit->imat, obedit->obmat); @@ -1074,7 +1073,6 @@ void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot) static int armature_subdivide_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; EditBone *newbone, *tbone; int cuts, i; @@ -1083,7 +1081,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op) /* loop over all editable bones */ // XXX the old code did this in reverse order though! - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) + CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, selected_editable_bones, bArmature *, arm) { for (i = cuts + 1; i > 1; i--) { /* compute cut ratio first */ diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 539d56a4ede..9fcf6ad4826 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -48,8 +48,10 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_global.h" #include "BKE_report.h" +#include "BKE_object.h" #include "RNA_access.h" #include "RNA_define.h" @@ -138,17 +140,16 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do /* exported for use in editors/object/ */ /* 0 == do center, 1 == center new, 2 == center cursor */ -void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around) +void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int around) { - Object *obedit = scene->obedit; // XXX get from context + const bool is_editmode = BKE_object_is_in_editmode(ob); EditBone *ebone; bArmature *arm = ob->data; float cent[3]; /* Put the armature into editmode */ - if (ob != obedit) { + if (is_editmode == false) { ED_armature_to_edit(arm); - obedit = NULL; /* we cant use this so behave as if there is no obedit */ } /* Find the centerpoint */ @@ -188,13 +189,13 @@ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int cente } /* Turn the list into an armature */ - if (obedit == NULL) { + if (is_editmode == false) { ED_armature_from_edit(arm); ED_armature_edit_free(arm); } /* Adjust object location for new centerpoint */ - if (centermode && obedit == NULL) { + if (centermode && (is_editmode == false)) { mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */ add_v3_v3(ob->loc, cent); } @@ -317,10 +318,10 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); /* can be NULL */ float cursor_local[3]; - const float *cursor = ED_view3d_cursor3d_get(scene, v3d); + const View3DCursor *cursor = ED_view3d_cursor3d_get(scene, v3d); invert_m4_m4(ob->imat, ob->obmat); - copy_v3_v3(cursor_local, cursor); + copy_v3_v3(cursor_local, cursor->location); mul_m4_v3(ob->imat, cursor_local); @@ -630,25 +631,39 @@ static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points) /* bone adding between selected joints */ static int armature_fill_bones_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = (obedit) ? obedit->data : NULL; + Object *obedit_active = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ListBase points = {NULL, NULL}; EditBone *newbone = NULL; int count; + bool mixed_object_error = false; /* sanity checks */ - if (ELEM(NULL, obedit, arm)) + if (ELEM(NULL, obedit_active, obedit_active->data)) { return OPERATOR_CANCELLED; + } /* loop over all bones, and only consider if visible */ - CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) + bArmature *arm = NULL; + CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter) { - if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) + bool check = false; + if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) { fill_add_joint(ebone, 0, &points); - if (ebone->flag & BONE_TIPSEL) + check = true; + } + if (ebone->flag & BONE_TIPSEL) { fill_add_joint(ebone, 1, &points); + check = true; + } + + if (check) { + if (arm && (arm != arm_iter)) { + mixed_object_error = true; + } + arm = arm_iter; + } } CTX_DATA_END; @@ -663,7 +678,25 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No joints selected"); return OPERATOR_CANCELLED; } - else if (count == 1) { + else if (mixed_object_error) { + BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected"); + BLI_freelistN(&points); + return OPERATOR_CANCELLED; + } + + Object *obedit = NULL; + { + ViewLayer *view_layer = CTX_data_view_layer(C); + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_EDIT, ob_iter) { + if (ob_iter->data == arm) { + obedit = ob_iter; + } + } + FOREACH_OBJECT_IN_MODE_END; + } + BLI_assert(obedit != NULL); + + if (count == 1) { EditBonePoint *ebp; float curs[3]; @@ -672,7 +705,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) /* Get points - cursor (tail) */ invert_m4_m4(obedit->imat, obedit->obmat); - mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); + mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)->location); /* Create a bone */ newbone = add_points_bone(obedit, ebp->vec, curs); @@ -710,7 +743,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) /* get cursor location */ invert_m4_m4(obedit->imat, obedit->obmat); - mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); + mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)->location); /* get distances */ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs); @@ -1301,38 +1334,50 @@ static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p) /* only editmode! */ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) { - bArmature *arm; EditBone *curBone, *ebone_next; - Object *obedit = CTX_data_edit_object(C); - bool changed = false; - arm = obedit->data; + bool changed_multi = false; /* cancel if nothing selected */ if (CTX_DATA_COUNT(C, selected_bones) == 0) return OPERATOR_CANCELLED; - armature_select_mirrored(arm); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + bArmature *arm = obedit->data; + bool changed = false; + + armature_select_mirrored(arm); + + BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm); + + for (curBone = arm->edbo->first; curBone; curBone = ebone_next) { + ebone_next = curBone->next; + if (arm->layer & curBone->layer) { + if (curBone->flag & BONE_SELECTED) { + if (curBone == arm->act_edbone) arm->act_edbone = NULL; + ED_armature_ebone_remove(arm, curBone); + changed = true; + } + } + } + + if (changed) { + changed_multi = true; - BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm); + ED_armature_edit_sync_selection(arm->edbo); + BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); - for (curBone = arm->edbo->first; curBone; curBone = ebone_next) { - ebone_next = curBone->next; - if (arm->layer & curBone->layer) { - if (curBone->flag & BONE_SELECTED) { - if (curBone == arm->act_edbone) arm->act_edbone = NULL; - ED_armature_ebone_remove(arm, curBone); - changed = true; - } + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } } + MEM_freeN(objects); - if (!changed) + if (!changed_multi) { return OPERATOR_CANCELLED; - - ED_armature_edit_sync_selection(arm->edbo); - BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + } return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 288d9f0f86b..1fe729b7c4b 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -137,18 +137,7 @@ void POSE_OT_rotation_mode_set(struct wmOperatorType *ot); void POSE_OT_quaternions_flip(struct wmOperatorType *ot); void POSE_OT_bone_layers(struct wmOperatorType *ot); - -/* ******************************************************* */ -/* Etch-A-Ton (Skeleton Sketching) Operators */ - -void SKETCH_OT_gesture(struct wmOperatorType *ot); -void SKETCH_OT_delete(struct wmOperatorType *ot); -void SKETCH_OT_draw_stroke(struct wmOperatorType *ot); -void SKETCH_OT_draw_preview(struct wmOperatorType *ot); -void SKETCH_OT_finish_stroke(struct wmOperatorType *ot); -void SKETCH_OT_cancel_stroke(struct wmOperatorType *ot); -void SKETCH_OT_convert(struct wmOperatorType *ot); -void SKETCH_OT_select(struct wmOperatorType *ot); +void POSE_OT_toggle_bone_selection_overlay(struct wmOperatorType *ot); /* ******************************************************* */ /* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */ @@ -225,7 +214,6 @@ void POSE_OT_propagate(struct wmOperatorType *ot); */ EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct EditBone *parent, struct Bone *actBone); -bool BIF_sk_selectStroke(struct bContext *C, const int mval[2], const bool extend); /* duplicate method */ void preEditBoneDuplicate(struct ListBase *editbones); @@ -248,10 +236,15 @@ void armature_select_mirrored_ex(struct bArmature *arm, const int flag); void armature_select_mirrored(struct bArmature *arm); void armature_tag_unselect(struct bArmature *arm); -void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel); +void *get_nearest_bone( + struct bContext *C, const int xy[2], bool findunsel, + struct Base **r_base); + void *get_bone_from_selectbuffer( - struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits, - bool findunsel, bool do_nearest); + struct Base **bases, uint bases_len, + bool is_editmode, const unsigned int *buffer, short hits, + bool findunsel, bool do_nearest, + struct Base **r_base); int bone_looper(struct Object *ob, struct Bone *bone, void *data, int (*bone_func)(struct Object *, struct Bone *, void *)); diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index c49e9a2b820..1a5e9e38099 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -48,11 +48,12 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_modifier.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -378,7 +379,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *op) BLI_freelistN(&bones_names); /* since we renamed stuff... */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* copied from #rna_Bone_update_renamed */ /* redraw view */ @@ -432,7 +433,7 @@ static int armature_autoside_names_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* since we renamed stuff... */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 31a22b41f54..cee99c3b8f8 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -85,16 +85,6 @@ void ED_operatortypes_armature(void) WM_operatortype_append(ARMATURE_OT_armature_layers); WM_operatortype_append(ARMATURE_OT_bone_layers); - /* SKETCH */ - WM_operatortype_append(SKETCH_OT_gesture); - WM_operatortype_append(SKETCH_OT_delete); - WM_operatortype_append(SKETCH_OT_draw_stroke); - WM_operatortype_append(SKETCH_OT_draw_preview); - WM_operatortype_append(SKETCH_OT_finish_stroke); - WM_operatortype_append(SKETCH_OT_cancel_stroke); - WM_operatortype_append(SKETCH_OT_convert); - WM_operatortype_append(SKETCH_OT_select); - /* POSE */ WM_operatortype_append(POSE_OT_hide); WM_operatortype_append(POSE_OT_reveal); @@ -142,6 +132,8 @@ void ED_operatortypes_armature(void) WM_operatortype_append(POSE_OT_bone_layers); + WM_operatortype_append(POSE_OT_toggle_bone_selection_overlay); + WM_operatortype_append(POSE_OT_propagate); /* POSELIB */ @@ -204,23 +196,6 @@ void ED_keymap_armature(wmKeyConfig *keyconf) keymap = WM_keymap_find(keyconf, "Armature", 0, 0); keymap->poll = ED_operator_editarmature; - /* Armature -> Etch-A-Ton ------------------------ */ - WM_keymap_add_item(keymap, "SKETCH_OT_delete", XKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "SKETCH_OT_delete", DELKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "SKETCH_OT_finish_stroke", RIGHTMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "SKETCH_OT_cancel_stroke", ESCKEY, KM_PRESS, 0, 0); - /* Already part of view3d select */ - //WM_keymap_add_item(keymap, "SKETCH_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); - - /* sketch poll checks mode */ - WM_keymap_add_item(keymap, "SKETCH_OT_gesture", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", LEFTMOUSE, KM_PRESS, 0, 0); - kmi = WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "snap", true); - WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, 0, 0); - kmi = WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "snap", true); - /* only set in editmode armature, by space_view3d listener */ kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_hide", HKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "unselected", false); @@ -390,6 +365,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ARMATURE_OT_layers_show_all", ACCENTGRAVEKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_armature_layers", MKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "POSE_OT_bone_layers", MKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "POSE_OT_toggle_bone_selection_overlay", ZKEY, KM_PRESS, 0, 0); /* special transforms: */ /* 1) envelope/b-bone size */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 95c8b1d5460..5d6c383b24b 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -47,12 +47,15 @@ #include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -370,7 +373,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (base->object->adt) { if (ob->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - ob->adt = BKE_animdata_copy(bmain, base->object->adt, false); + ob->adt = BKE_animdata_copy(bmain, base->object->adt, false, true); } else { /* merge in data - we'll fix the drivers manually */ @@ -381,7 +384,7 @@ int join_armature_exec(bContext *C, wmOperator *op) if (curarm->adt) { if (arm->adt == NULL) { /* no animdata, so just use a copy of the whole thing */ - arm->adt = BKE_animdata_copy(bmain, curarm->adt, false); + arm->adt = BKE_animdata_copy(bmain, curarm->adt, false, true); } else { /* merge in data - we'll fix the drivers manually */ @@ -390,12 +393,12 @@ int join_armature_exec(bContext *C, wmOperator *op) } /* Free the old object data */ - ED_base_object_free_and_unlink(bmain, scene, base); + ED_object_base_free_and_unlink(bmain, scene, base->object); } } CTX_DATA_END; - DAG_relations_tag_update(bmain); /* because we removed object(s) */ + DEG_relations_tag_update(bmain); /* because we removed object(s) */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); @@ -569,6 +572,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Object *obedit = CTX_data_edit_object(C); Object *oldob, *newob; Base *oldbase, *newbase; @@ -592,14 +596,18 @@ static int separate_armature_exec(bContext *C, wmOperator *op) /* TODO: use context iterators for this? */ CTX_DATA_BEGIN(C, Base *, base, visible_bases) { - if (base->object == obedit) base->flag |= SELECT; - else base->flag &= ~SELECT; + if (base->object == obedit) { + ED_object_base_select(base, BA_SELECT); + } + else { + ED_object_base_select(base, BA_DESELECT); + } } CTX_DATA_END; /* 1) store starting settings and exit editmode */ oldob = obedit; - oldbase = BASACT; + oldbase = view_layer->basact; oldob->mode &= ~OB_MODE_POSE; //oldbase->flag &= ~OB_POSEMODE; @@ -607,11 +615,11 @@ static int separate_armature_exec(bContext *C, wmOperator *op) ED_armature_edit_free(obedit->data); /* 2) duplicate base */ - newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */ - DAG_relations_tag_update(bmain); + newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, USER_DUP_ARM); /* only duplicate linked armature */ + DEG_relations_tag_update(bmain); newob = newbase->object; - newbase->flag &= ~SELECT; + newbase->flag &= ~BASE_SELECTED; /* 3) remove bones that shouldn't still be around on both armatures */ @@ -622,8 +630,8 @@ static int separate_armature_exec(bContext *C, wmOperator *op) /* 4) fix links before depsgraph flushes */ // err... or after? separated_armature_fix_links(oldob, newob); - DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */ - DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */ + DEG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */ + DEG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */ /* 5) restore original conditions */ diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index a4e916b8e63..95acc8ab6ba 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -29,6 +29,8 @@ * \ingroup edarmature */ +#include "MEM_guardedalloc.h" + #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -39,7 +41,9 @@ #include "BKE_context.h" #include "BKE_action.h" +#include "BKE_object.h" #include "BKE_report.h" +#include "BKE_layer.h" #include "BIF_gl.h" @@ -53,6 +57,8 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "DEG_depsgraph.h" + #include "armature_intern.h" /* utility macros for storing a temp int in the bone (selection flag) */ @@ -61,27 +67,84 @@ /* **************** PoseMode & EditMode Selection Buffer Queries *************************** */ -/* only for opengl selection indices */ -Bone *ED_armature_bone_find_index(Object *ob, int index) +Base *ED_armature_base_and_ebone_from_select_buffer( + Base **bases, uint bases_len, int hit, EditBone **r_ebone) { - bPoseChannel *pchan; - if (ob->pose == NULL) return NULL; - index >>= 16; // bone selection codes use left 2 bytes + const uint hit_object = hit & 0xFFFF; + Base *base = NULL; + EditBone *ebone = NULL; + /* TODO(campbell): optimize, eg: sort & binary search. */ + for (uint base_index = 0; base_index < bases_len; base_index++) { + if (bases[base_index]->object->select_color == hit_object) { + base = bases[base_index]; + break; + } + } + if (base != NULL) { + const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + bArmature *arm = base->object->data; + ebone = BLI_findlink(arm->edbo, hit_bone); + } + *r_ebone = ebone; + return base; +} - pchan = BLI_findlink(&ob->pose->chanbase, index); - return pchan ? pchan->bone : NULL; +Object *ED_armature_object_and_ebone_from_select_buffer( + Object **objects, uint objects_len, int hit, EditBone **r_ebone) +{ + const uint hit_object = hit & 0xFFFF; + Object *ob = NULL; + EditBone *ebone = NULL; + /* TODO(campbell): optimize, eg: sort & binary search. */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + if (objects[ob_index]->select_color == hit_object) { + ob = objects[ob_index]; + break; + } + } + if (ob != NULL) { + const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + bArmature *arm = ob->data; + ebone = BLI_findlink(arm->edbo, hit_bone); + } + *r_ebone = ebone; + return ob; +} + +Base *ED_armature_base_and_bone_from_select_buffer( + Base **bases, uint bases_len, int hit, Bone **r_bone) +{ + const uint hit_object = hit & 0xFFFF; + Base *base = NULL; + Bone *bone = NULL; + /* TODO(campbell): optimize, eg: sort & binary search. */ + for (uint base_index = 0; base_index < bases_len; base_index++) { + if (bases[base_index]->object->select_color == hit_object) { + base = bases[base_index]; + break; + } + } + if (base != NULL) { + if (base->object->pose != NULL) { + const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);; + bone = pchan ? pchan->bone : NULL; + } + } + *r_bone = bone; + return base; } /* See if there are any selected bones in this buffer */ /* only bones from base are checked on */ void *get_bone_from_selectbuffer( - Scene *scene, Base *base, const unsigned int *buffer, short hits, - bool findunsel, bool do_nearest) + Base **bases, uint bases_len, bool is_editmode, const unsigned int *buffer, short hits, + bool findunsel, bool do_nearest, Base **r_base) { - Object *obedit = scene->obedit; // XXX get from context Bone *bone; EditBone *ebone; void *firstunSel = NULL, *firstSel = NULL, *data; + Base *firstunSel_base = NULL, *firstSel_base = NULL; unsigned int hitresult; short i; bool takeNext = false; @@ -92,15 +155,14 @@ void *get_bone_from_selectbuffer( if (!(hitresult & BONESEL_NOSEL)) { if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ + Base *base = NULL; bool sel; hitresult &= ~(BONESEL_ANY); /* Determine what the current bone is */ - if (obedit == NULL || base->object != obedit) { - /* no singular posemode, so check for correct object */ - if (base->selcol == (hitresult & 0xFFFF)) { - bone = ED_armature_bone_find_index(base->object, hitresult); - + if (is_editmode == false) { + base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone); + if (bone != NULL) { if (findunsel) sel = (bone->flag & BONE_SELECTED); else @@ -114,9 +176,7 @@ void *get_bone_from_selectbuffer( } } else { - bArmature *arm = obedit->data; - - ebone = BLI_findlink(arm->edbo, hitresult); + base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); if (findunsel) sel = (ebone->flag & BONE_SELECTED); else @@ -130,11 +190,15 @@ void *get_bone_from_selectbuffer( if (do_nearest) { if (minsel > buffer[4 * i + 1]) { firstSel = data; + firstSel_base = base; minsel = buffer[4 * i + 1]; } } else { - if (!firstSel) firstSel = data; + if (!firstSel) { + firstSel = data; + firstSel_base = base; + } takeNext = 1; } } @@ -142,12 +206,19 @@ void *get_bone_from_selectbuffer( if (do_nearest) { if (minunsel > buffer[4 * i + 1]) { firstunSel = data; + firstunSel_base = base; minunsel = buffer[4 * i + 1]; } } else { - if (!firstunSel) firstunSel = data; - if (takeNext) return data; + if (!firstunSel) { + firstunSel = data; + firstunSel_base = base; + } + if (takeNext) { + *r_base = base; + return data; + } } } } @@ -155,16 +226,22 @@ void *get_bone_from_selectbuffer( } } - if (firstunSel) + if (firstunSel) { + *r_base = firstunSel_base; return firstunSel; - else + } + else { + *r_base = firstSel_base; return firstSel; + } } /* used by posemode as well editmode */ /* only checks scene->basact! */ /* x and y are mouse coords (area space) */ -void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel) +void *get_nearest_bone( + bContext *C, const int xy[2], bool findunsel, + Base **r_base) { ViewContext vc; rcti rect; @@ -179,9 +256,27 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel) hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST); - if (hits > 0) - return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel, true); + *r_base = NULL; + + if (hits > 0) { + uint bases_len = 0; + Base **bases; + + if (vc.obedit != NULL) { + bases = BKE_view_layer_array_from_bases_in_mode( + vc.view_layer, &bases_len, { + .object_mode = OB_MODE_EDIT}); + } + else { + bases = BKE_object_pose_base_array_get(vc.view_layer, &bases_len); + } + + void *bone = get_bone_from_selectbuffer( + bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base); + MEM_freeN(bases); + return bone; + } return NULL; } @@ -194,16 +289,17 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv bArmature *arm; EditBone *bone, *curBone, *next; const bool extend = RNA_boolean_get(op->ptr, "extend"); - Object *obedit = CTX_data_edit_object(C); - arm = obedit->data; view3d_operator_needs_opengl(C); - bone = get_nearest_bone(C, event->mval, !extend); + Base *base = NULL; + bone = get_nearest_bone(C, event->mval, !extend, &base); if (!bone) return OPERATOR_CANCELLED; + arm = base->object->data; + /* Select parents */ for (curBone = bone; curBone; curBone = next) { if ((curBone->flag & BONE_UNSELECTABLE) == 0) { @@ -246,7 +342,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv ED_armature_edit_sync_selection(arm->edbo); - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); return OPERATOR_FINISHED; } @@ -292,36 +388,42 @@ static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const /* note that BONE ROOT only gets drawn for root bones (or without IK) */ static EditBone *get_nearest_editbonepoint( ViewContext *vc, - bool findunsel, bool use_cycle, int *r_selmask) + bool findunsel, bool use_cycle, + Base **r_base, int *r_selmask) { - bArmature *arm = (bArmature *)vc->obedit->data; - EditBone *ebone_next_act = arm->act_edbone; - - EditBone *ebone; - rcti rect; - unsigned int buffer[MAXPICKBUF]; - unsigned int hitresult, besthitresult = BONESEL_NOSEL; - int i, mindep = 5; - int hits12, hits5 = 0; - - static int last_mval[2] = {-100, -100}; + uint buffer[MAXPICKBUF]; + struct { + uint hitresult; + Base *base; + EditBone *ebone; + } best = { + .hitresult = BONESEL_NOSEL, + .base = NULL, + .ebone = NULL, + }; /* find the bone after the current active bone, so as to bump up its chances in selection. * this way overlapping bones will cycle selection state as with objects. */ - if (ebone_next_act && - EBONE_VISIBLE(arm, ebone_next_act) && - ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) + EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone; { - ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first; - } - else { - ebone_next_act = NULL; + bArmature *arm = (bArmature *)vc->obedit->data; + if (ebone_next_act && + EBONE_VISIBLE(arm, ebone_next_act) && + ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) + { + ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first; + } + else { + ebone_next_act = NULL; + } } bool do_nearest = false; /* define if we use solid nearest select or not */ if (use_cycle) { + static int last_mval[2] = {-100, -100}; + if (vc->v3d->drawtype > OB_WIRE) { do_nearest = true; if (len_manhattan_v2v2_int(vc->mval, last_mval) < 3) { @@ -337,52 +439,64 @@ static EditBone *get_nearest_editbonepoint( } /* matching logic from 'mixed_bones_object_selectbuffer' */ - const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); int hits = 0; /* we _must_ end cache before return, use 'goto cache_end' */ view3d_opengl_select_cache_begin(); - BLI_rcti_init_pt_radius(&rect, vc->mval, 12); - hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode); - if (hits12 == 1) { - hits = selectbuffer_ret_hits_12(buffer, hits12); - goto cache_end; - } - else if (hits12 > 0) { - int offs; - - offs = 4 * hits12; - BLI_rcti_init_pt_radius(&rect, vc->mval, 5); - hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode); - - if (hits5 == 1) { - hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); + { + const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); + rcti rect; + BLI_rcti_init_pt_radius(&rect, vc->mval, 12); + const int hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode); + if (hits12 == 1) { + hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; } + else if (hits12 > 0) { + int offs; + + offs = 4 * hits12; + BLI_rcti_init_pt_radius(&rect, vc->mval, 5); + const int hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode); + + if (hits5 == 1) { + hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); + goto cache_end; + } - if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); goto cache_end; } - else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; } + if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); goto cache_end; } + else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; } + } } cache_end: view3d_opengl_select_cache_end(); + uint bases_len; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc->view_layer, &bases_len); + /* See if there are any selected bones in this group */ if (hits > 0) { - if (hits == 1) { - if (!(buffer[3] & BONESEL_NOSEL)) - besthitresult = buffer[3]; + if (!(buffer[3] & BONESEL_NOSEL)) { + best.hitresult = buffer[3]; + best.base = ED_armature_base_and_ebone_from_select_buffer( + bases, bases_len, best.hitresult, &best.ebone); + } } else { - for (i = 0; i < hits; i++) { - hitresult = buffer[3 + (i * 4)]; + int dep_min = 5; + for (int i = 0; i < hits; i++) { + const uint hitresult = buffer[3 + (i * 4)]; if (!(hitresult & BONESEL_NOSEL)) { - int dep; - - ebone = BLI_findlink(arm->edbo, hitresult & ~BONESEL_ANY); + Base *base = NULL; + EditBone *ebone; + base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); + /* If this fails, selection code is setting the selection ID's incorrectly. */ + BLI_assert(base && ebone); + int dep; /* clicks on bone points get advantage */ if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) { /* but also the unselected one */ @@ -415,29 +529,36 @@ cache_end: dep -= 1; } - if (dep < mindep) { - mindep = dep; - besthitresult = hitresult; + if (dep < dep_min) { + dep_min = dep; + best.hitresult = hitresult; + best.base = base; + best.ebone = ebone; } } } } - if (!(besthitresult & BONESEL_NOSEL)) { - - ebone = BLI_findlink(arm->edbo, besthitresult & ~BONESEL_ANY); + if (!(best.hitresult & BONESEL_NOSEL)) { + *r_base = best.base; *r_selmask = 0; - if (besthitresult & BONESEL_ROOT) + if (best.hitresult & BONESEL_ROOT) { *r_selmask |= BONE_ROOTSEL; - if (besthitresult & BONESEL_TIP) + } + if (best.hitresult & BONESEL_TIP) { *r_selmask |= BONE_TIPSEL; - if (besthitresult & BONESEL_BONE) + } + if (best.hitresult & BONESEL_BONE) { *r_selmask |= BONE_SELECTED; - return ebone; + } + MEM_freeN(bases); + return best.ebone; } } *r_selmask = 0; + *r_base = NULL; + MEM_freeN(bases); return NULL; } @@ -466,6 +587,23 @@ void ED_armature_edit_deselect_all_visible(Object *obedit) ED_armature_edit_sync_selection(arm->edbo); } + +void ED_armature_edit_deselect_all_multi(struct Object **objects, uint objects_len) +{ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ED_armature_edit_deselect_all(obedit); + } +} + +void ED_armature_edit_deselect_all_visible_multi(struct Object **objects, uint objects_len) +{ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ED_armature_edit_deselect_all_visible(obedit); + } +} + /* accounts for connected parents */ static int ebone_select_flag(EditBone *ebone) { @@ -480,25 +618,25 @@ static int ebone_select_flag(EditBone *ebone) /* context: editmode armature in view3d */ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { - Object *obedit = CTX_data_edit_object(C); ViewContext vc; EditBone *nearBone = NULL; int selmask; + Base *basact = NULL; ED_view3d_viewcontext_init(C, &vc); vc.mval[0] = mval[0]; vc.mval[1] = mval[1]; - if (BIF_sk_selectStroke(C, mval, extend)) { - return true; - } - - nearBone = get_nearest_editbonepoint(&vc, true, true, &selmask); + nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask); if (nearBone) { - bArmature *arm = obedit->data; + ED_view3d_viewcontext_init_object(&vc, basact->object); + bArmature *arm = vc.obedit->data; if (!extend && !deselect && !toggle) { - ED_armature_edit_deselect_all(obedit); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, &objects_len); + ED_armature_edit_deselect_all_multi(objects, objects_len); + MEM_freeN(objects); } /* by definition the non-root connected bones have no root point drawn, @@ -576,9 +714,14 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b if (ebone_select_flag(nearBone)) { arm->act_edbone = nearBone; } + + if (vc.view_layer->basact != basact) { + vc.view_layer->basact = basact; + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, vc.scene); + } } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); return true; } @@ -1291,17 +1434,23 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const EditBone *ebone_isect_parent = NULL; EditBone *ebone_isect_child[2]; bool changed; + Base *base_dst = NULL; view3d_operator_needs_opengl(C); ebone_src = arm->act_edbone; - ebone_dst = get_nearest_bone(C, event->mval, false); + ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst); /* fallback to object selection */ if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) { return OPERATOR_PASS_THROUGH; } + if (base_dst && base_dst->object != obedit) { + /* Disconnected, ignore. */ + return OPERATOR_CANCELLED; + } + ebone_isect_child[0] = ebone_src; ebone_isect_child[1] = ebone_dst; diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 8ab8d60af75..463e00957e6 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -43,12 +43,15 @@ #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_object_deform.h" #include "BKE_report.h" #include "BKE_subsurf.h" #include "BKE_modifier.h" +#include "DEG_depsgraph.h" + #include "ED_armature.h" #include "ED_mesh.h" @@ -57,13 +60,9 @@ #include "armature_intern.h" #include "meshlaplacian.h" -#if 0 -#include "reeb.h" -#endif - /* ********************************** Bone Skinning *********************************************** */ -static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap) +static int bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap) { /* Bones that are deforming * are regarded to be "skinnable" and are eligible for @@ -89,9 +88,9 @@ static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap) */ Bone ***hbone; int a, segments; - struct { Object *armob; void *list; int heat; } *data = datap; + struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap; - if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) { + if (!(data->is_weight_paint) || !(bone->flag & BONE_HIDDEN_P)) { if (!(bone->flag & BONE_NO_DEFORM)) { if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name)) segments = bone->segments; @@ -154,18 +153,17 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) */ bDeformGroup ***hgroup, *defgroup = NULL; int a, segments; - struct { Object *armob; void *list; int heat; } *data = datap; - int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); + struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap; bArmature *arm = data->armob->data; - if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) { + if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) { if (!(bone->flag & BONE_NO_DEFORM)) { if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name)) segments = bone->segments; else segments = 1; - if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) { + if (!data->is_weight_paint || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) { if (!(defgroup = defgroup_find_name(ob, bone->name))) { defgroup = BKE_object_defgroup_add_name(ob, bone->name); } @@ -189,9 +187,10 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) return 0; } -static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, - bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, - float (*root)[3], float (*tip)[3], const int *selected, float scale) +static void envelope_bone_weighting( + Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, + bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, + float (*root)[3], float (*tip)[3], const int *selected, float scale) { /* Create vertex group weights from envelopes */ @@ -247,8 +246,9 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i } } -static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, - int heat, const bool mirror) +static void add_verts_to_dgroups( + ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, + int heat, const bool mirror) { /* This functions implements the automatic computation of vertex group * weights, either through envelopes or using a heat equilibrium. @@ -272,12 +272,13 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, float (*root)[3], (*tip)[3], (*verts)[3]; int *selected; int numbones, vertsfilled = 0, i, j, segments = 0; - int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); - struct { Object *armob; void *list; int heat; } looper_data; + const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); + struct { Object *armob; void *list; int heat; bool is_weight_paint; } looper_data; looper_data.armob = par; looper_data.heat = heat; looper_data.list = NULL; + looper_data.is_weight_paint = wpmode; /* count the number of skinnable bones */ numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); @@ -372,7 +373,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if (wpmode) { /* if in weight paint mode, use final verts from derivedmesh */ - DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + DerivedMesh *dm = mesh_get_derived_final(depsgraph, scene, ob, CD_MASK_BAREMESH); if (dm->foreachMappedVert) { mesh_get_mapped_verts_coords(dm, verts, mesh->totvert); @@ -400,15 +401,17 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if (heat) { const char *error = NULL; - heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip, - root, tip, selected, &error); + heat_bone_weighting( + ob, mesh, verts, numbones, dgrouplist, dgroupflip, + root, tip, selected, &error); if (error) { BKE_report(reports, RPT_WARNING, error); } } else { - envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist, - dgroupflip, root, tip, selected, mat4_to_scale(par->obmat)); + envelope_bone_weighting( + ob, mesh, verts, numbones, bonelist, dgrouplist, + dgroupflip, root, tip, selected, mat4_to_scale(par->obmat)); } /* only generated in some cases but can call anyway */ @@ -424,8 +427,9 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, MEM_freeN(verts); } -void ED_object_vgroup_calc_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, - const int mode, const bool mirror) +void ED_object_vgroup_calc_from_armature( + ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, + const int mode, const bool mirror) { /* Lets try to create some vertex groups * based on the bones of the parent armature. @@ -451,6 +455,6 @@ void ED_object_vgroup_calc_from_armature(ReportList *reports, Scene *scene, Obje * that are populated with the vertices for which the * bone is closest. */ - add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror); + add_verts_to_dgroups(reports, depsgraph, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror); } } diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index f0e4d5e1102..a8116ce26cf 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -39,11 +39,12 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_main.h" +#include "DEG_depsgraph.h" + #include "ED_armature.h" #include "ED_util.h" @@ -684,7 +685,7 @@ void ED_armature_from_edit(bArmature *arm) } } - DAG_id_tag_update(&arm->id, 0); + DEG_id_tag_update(&arm->id, 0); } void ED_armature_edit_free(struct bArmature *arm) @@ -715,8 +716,6 @@ void ED_armature_to_edit(bArmature *arm) ED_armature_edit_free(arm); arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature"); arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, NULL, arm->act_bone); - -// BIF_freeTemplates(); /* force template update when entering editmode */ } /* *************************************************************** */ diff --git a/source/blender/editors/armature/editarmature_generate.c b/source/blender/editors/armature/editarmature_generate.c deleted file mode 100644 index f0135676523..00000000000 --- a/source/blender/editors/armature/editarmature_generate.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * ***** 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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/armature/editarmature_generate.c - * \ingroup edarmature - */ - -#include "DNA_scene_types.h" -#include "DNA_armature_types.h" - -#include "BLI_math.h" -#include "BLI_graph.h" - -#include "ED_armature.h" -#include "BIF_generate.h" - -void setBoneRollFromNormal(EditBone *bone, const float no[3], float UNUSED(invmat[4][4]), float tmat[3][3]) -{ - if (no != NULL && !is_zero_v3(no)) { - float normal[3]; - - copy_v3_v3(normal, no); - mul_m3_v3(tmat, normal); - - bone->roll = ED_armature_ebone_roll_to_vector(bone, normal, false); - } -} - -float calcArcCorrelation(BArcIterator *iter, int start, int end, float v0[3], float n[3]) -{ - int len = 2 + abs(end - start); - - if (len > 2) { - float avg_t = 0.0f; - float s_t = 0.0f; - float s_xyz = 0.0f; - int i; - - /* First pass, calculate average */ - for (i = start; i <= end; i++) { - float v[3]; - - IT_peek(iter, i); - sub_v3_v3v3(v, iter->p, v0); - avg_t += dot_v3v3(v, n); - } - - avg_t /= dot_v3v3(n, n); - avg_t += 1.0f; /* adding start (0) and end (1) values */ - avg_t /= len; - - /* Second pass, calculate s_xyz and s_t */ - for (i = start; i <= end; i++) { - float v[3], d[3]; - float dt; - - IT_peek(iter, i); - sub_v3_v3v3(v, iter->p, v0); - project_v3_v3v3(d, v, n); - sub_v3_v3(v, d); - - dt = len_v3(d) - avg_t; - - s_t += dt * dt; - s_xyz += dot_v3v3(v, v); - } - - /* adding start(0) and end(1) values to s_t */ - s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t); - - return 1.0f - s_xyz / s_t; - } - else { - return 1.0f; - } -} - -int nextFixedSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float UNUSED(head[3]), float p[3]) -{ - static float stroke_length = 0; - static float current_length; - static char n; - float *v1, *v2; - float length_threshold; - int i; - - if (stroke_length == 0) { - current_length = 0; - - IT_peek(iter, start); - v1 = iter->p; - - for (i = start + 1; i <= end; i++) { - IT_peek(iter, i); - v2 = iter->p; - - stroke_length += len_v3v3(v1, v2); - - v1 = v2; - } - - n = 0; - current_length = 0; - } - - n++; - - length_threshold = n * stroke_length / toolsettings->skgen_subdivision_number; - - IT_peek(iter, start); - v1 = iter->p; - - /* < and not <= because we don't care about end, it is P_EXACT anyway */ - for (i = start + 1; i < end; i++) { - IT_peek(iter, i); - v2 = iter->p; - - current_length += len_v3v3(v1, v2); - - if (current_length >= length_threshold) { - copy_v3_v3(p, v2); - return i; - } - - v1 = v2; - } - - stroke_length = 0; - - return -1; -} -int nextAdaptativeSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float head[3], float p[3]) -{ - float correlation_threshold = toolsettings->skgen_correlation_limit; - float *start_p; - float n[3]; - int i; - - IT_peek(iter, start); - start_p = iter->p; - - for (i = start + 2; i <= end; i++) { - /* Calculate normal */ - IT_peek(iter, i); - sub_v3_v3v3(n, iter->p, head); - - if (calcArcCorrelation(iter, start, i, start_p, n) < correlation_threshold) { - IT_peek(iter, i - 1); - copy_v3_v3(p, iter->p); - return i - 1; - } - } - - return -1; -} - -int nextLengthSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float head[3], float p[3]) -{ - float lengthLimit = toolsettings->skgen_length_limit; - int same = 1; - int i; - - i = start + 1; - while (i <= end) { - float *vec0; - float *vec1; - - IT_peek(iter, i - 1); - vec0 = iter->p; - - IT_peek(iter, i); - vec1 = iter->p; - - /* If lengthLimit hits the current segment */ - if (len_v3v3(vec1, head) > lengthLimit) { - if (same == 0) { - float dv[3], off[3]; - float a, b, c, f; - - /* Solve quadratic distance equation */ - sub_v3_v3v3(dv, vec1, vec0); - a = dot_v3v3(dv, dv); - - sub_v3_v3v3(off, vec0, head); - b = 2 * dot_v3v3(dv, off); - - c = dot_v3v3(off, off) - (lengthLimit * lengthLimit); - - f = (-b + sqrtf(b * b - 4 * a * c)) / (2 * a); - - //printf("a %f, b %f, c %f, f %f\n", a, b, c, f); - - if (isnan(f) == 0 && f < 1.0f) { - copy_v3_v3(p, dv); - mul_v3_fl(p, f); - add_v3_v3(p, vec0); - } - else { - copy_v3_v3(p, vec1); - } - } - else { - float dv[3]; - - sub_v3_v3v3(dv, vec1, vec0); - normalize_v3(dv); - - copy_v3_v3(p, dv); - mul_v3_fl(p, lengthLimit); - add_v3_v3(p, head); - } - - return i - 1; /* restart at lower bound */ - } - else { - i++; - same = 0; // Reset same - } - } - - return -1; -} - -EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *UNUSED(editbones), BArcIterator *iter, - float invmat[4][4], float tmat[3][3], NextSubdivisionFunc next_subdividion) -{ - EditBone *lastBone = NULL; - EditBone *child = NULL; - EditBone *parent = NULL; - float *normal = NULL; - float size_buffer = 1.2; - int bone_start = 0; - int end = iter->length; - int index; - - IT_head(iter); - - parent = ED_armature_ebone_add(arm, "Bone"); - copy_v3_v3(parent->head, iter->p); - - if (iter->size > FLT_EPSILON) { - parent->rad_head = iter->size * size_buffer; - } - - normal = iter->no; - - index = next_subdividion(toolsettings, iter, bone_start, end, parent->head, parent->tail); - while (index != -1) { - IT_peek(iter, index); - - child = ED_armature_ebone_add(arm, "Bone"); - copy_v3_v3(child->head, parent->tail); - child->parent = parent; - child->flag |= BONE_CONNECTED; - - if (iter->size > FLT_EPSILON) { - child->rad_head = iter->size * size_buffer; - parent->rad_tail = iter->size * size_buffer; - } - - /* going to next bone, fix parent */ - mul_m4_v3(invmat, parent->tail); - mul_m4_v3(invmat, parent->head); - setBoneRollFromNormal(parent, normal, invmat, tmat); - - parent = child; // new child is next parent - bone_start = index; // start next bone from current index - - normal = iter->no; /* use normal at head, not tail */ - - index = next_subdividion(toolsettings, iter, bone_start, end, parent->head, parent->tail); - } - - iter->tail(iter); - - copy_v3_v3(parent->tail, iter->p); - if (iter->size > FLT_EPSILON) { - parent->rad_tail = iter->size * size_buffer; - } - - /* fix last bone */ - mul_m4_v3(invmat, parent->tail); - mul_m4_v3(invmat, parent->head); - setBoneRollFromNormal(parent, iter->no, invmat, tmat); - lastBone = parent; - - return lastBone; -} diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c deleted file mode 100644 index ad0025955c2..00000000000 --- a/source/blender/editors/armature/editarmature_retarget.c +++ /dev/null @@ -1,2641 +0,0 @@ -/* - * ***** 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): Martin Poirier - * - * ***** END GPL LICENSE BLOCK ***** - * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...) - */ - -/** \file blender/editors/armature/editarmature_retarget.c - * \ingroup edarmature - */ - -#include "MEM_guardedalloc.h" - -#include "PIL_time.h" - -#include "DNA_armature_types.h" -#include "DNA_constraint_types.h" -#include "DNA_scene_types.h" -#include "DNA_object_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" - -#include "BKE_constraint.h" -#include "BKE_armature.h" -#include "BKE_context.h" - -#include "ED_armature.h" -#include "ED_undo.h" - -#include "BIF_retarget.h" - -#include "armature_intern.h" - -/************ RIG RETARGET DATA STRUCTURES ***************/ - -typedef struct MemoNode { - float weight; - int next; -} MemoNode; - -typedef struct RetargetParam { - RigGraph *rigg; - RigArc *iarc; - RigNode *inode_start; - bContext *context; -} RetargetParam; - -typedef enum { - RETARGET_LENGTH, - RETARGET_AGGRESSIVE -} RetargetMode; - -typedef enum { - METHOD_BRUTE_FORCE = 0, - METHOD_MEMOIZE = 1 -} RetargetMethod; - -typedef enum { - ARC_FREE = 0, - ARC_TAKEN = 1, - ARC_USED = 2 -} ArcUsageFlags; - -static RigGraph *GLOBAL_RIGG = NULL; - -/*******************************************************************************************************/ - -void exec_retargetArctoArc(TaskPool * __restrict pool, void *taskdata, int threadid); - -static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second); -float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]); - -/* two levels */ -#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX) - -/*********************************** EDITBONE UTILS ****************************************************/ - -static int countEditBoneChildren(ListBase *list, EditBone *parent) -{ - EditBone *ebone; - int count = 0; - - for (ebone = list->first; ebone; ebone = ebone->next) { - if (ebone->parent == parent) { - count++; - } - } - - return count; -} - -static EditBone *nextEditBoneChild(ListBase *list, EditBone *parent, int n) -{ - EditBone *ebone; - - for (ebone = list->first; ebone; ebone = ebone->next) { - if (ebone->parent == parent) { - if (n == 0) { - return ebone; - } - n--; - } - } - - return NULL; -} - -static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3]) -{ - float mat[3][3], nor[3]; - - sub_v3_v3v3(nor, bone->tail, bone->head); - - vec_roll_to_mat3(nor, roll, mat); - copy_v3_v3(up_axis, mat[2]); -} - -static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3]) -{ - float nor[3], new_up_axis[3], x_axis[3], z_axis[3]; - - copy_v3_v3(new_up_axis, old_up_axis); - mul_qt_v3(qrot, new_up_axis); - - sub_v3_v3v3(nor, bone->tail, bone->head); - - cross_v3_v3v3(x_axis, nor, aligned_axis); - cross_v3_v3v3(z_axis, x_axis, nor); - - normalize_v3(new_up_axis); - normalize_v3(x_axis); - normalize_v3(z_axis); - - if (dot_v3v3(new_up_axis, x_axis) < 0) { - negate_v3(x_axis); - } - - if (dot_v3v3(new_up_axis, z_axis) < 0) { - negate_v3(z_axis); - } - - if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) { - rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */ - return ED_armature_ebone_roll_to_vector(bone, x_axis, false); - } - else { - rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */ - return ED_armature_ebone_roll_to_vector(bone, z_axis, false); - } -} - -static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3]) -{ - if (previous == NULL) { - /* default to up_axis if no previous */ - return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); - } - else { - float new_up_axis[3]; - float vec_first[3], vec_second[3], normal[3]; - - if (previous->bone) { - sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head); - } - else if (previous->prev->bone) { - sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail); - } - else { - /* default to up_axis if first bone in the chain is an offset */ - return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); - } - - sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head); - - normalize_v3(vec_first); - normalize_v3(vec_second); - - cross_v3_v3v3(normal, vec_first, vec_second); - normalize_v3(normal); - - axis_angle_to_quat(qroll, vec_second, edge->up_angle); - - mul_qt_v3(qroll, normal); - - copy_v3_v3(new_up_axis, edge->up_axis); - mul_qt_v3(qrot, new_up_axis); - - normalize_v3(new_up_axis); - - /* real qroll between normal and up_axis */ - rotation_between_vecs_to_quat(qroll, new_up_axis, normal); - - return ED_armature_ebone_roll_to_vector(edge->bone, normal, false); - } -} - -float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]) -{ - float new_up_axis[3]; - - copy_v3_v3(new_up_axis, old_up_axis); - mul_qt_v3(qrot, new_up_axis); - - return ED_armature_ebone_roll_to_vector(bone, new_up_axis, false); -} - -/************************************ DESTRUCTORS ******************************************************/ - -static void RIG_freeRigArc(BArc *arc) -{ - BLI_freelistN(&((RigArc *)arc)->edges); -} - -void RIG_freeRigGraph(BGraph *rg) -{ - RigGraph *rigg = (RigGraph *)rg; - BNode *node; - BArc *arc; - - BLI_task_pool_free(rigg->task_pool); - BLI_task_scheduler_free(rigg->task_scheduler); - - if (rigg->link_mesh) { - REEB_freeGraph(rigg->link_mesh); - } - - for (arc = rg->arcs.first; arc; arc = arc->next) { - RIG_freeRigArc(arc); - } - BLI_freelistN(&rg->arcs); - - for (node = rg->nodes.first; node; node = node->next) { - BLI_freeNode(rg, (BNode *)node); - } - BLI_freelistN(&rg->nodes); - - BLI_freelistN(&rigg->controls); - - BLI_ghash_free(rigg->bones_map, NULL, NULL); - BLI_ghash_free(rigg->controls_map, NULL, NULL); - - if (rigg->flag & RIG_FREE_BONELIST) { - BLI_freelistN(rigg->editbones); - MEM_freeN(rigg->editbones); - } - - MEM_freeN(rg); -} - -/************************************* ALLOCATORS ******************************************************/ - -static RigGraph *newRigGraph(void) -{ - RigGraph *rg; - int totthread; - - rg = MEM_callocN(sizeof(RigGraph), "rig graph"); - - rg->head = NULL; - - rg->bones_map = BLI_ghash_str_new("newRigGraph bones gh"); - rg->controls_map = BLI_ghash_str_new("newRigGraph cont gh"); - - rg->free_arc = RIG_freeRigArc; - rg->free_node = NULL; - -#ifdef USE_THREADS - totthread = TASK_SCHEDULER_AUTO_THREADS; -#else - totthread = TASK_SCHEDULER_SINGLE_THREAD; -#endif - - rg->task_scheduler = BLI_task_scheduler_create(totthread); - rg->task_pool = BLI_task_pool_create(rg->task_scheduler, NULL); - - return rg; -} - -static RigArc *newRigArc(RigGraph *rg) -{ - RigArc *arc; - - arc = MEM_callocN(sizeof(RigArc), "rig arc"); - arc->count = 0; - BLI_addtail(&rg->arcs, arc); - - return arc; -} - -static RigControl *newRigControl(RigGraph *rg) -{ - RigControl *ctrl; - - ctrl = MEM_callocN(sizeof(RigControl), "rig control"); - - BLI_addtail(&rg->controls, ctrl); - - return ctrl; -} - -static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3]) -{ - RigNode *node; - node = MEM_callocN(sizeof(RigNode), "rig node"); - BLI_addtail(&rg->nodes, node); - - copy_v3_v3(node->p, p); - node->degree = 1; - node->arcs = NULL; - - arc->head = node; - - return node; -} - -static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node) -{ - node->degree++; - - arc->head = node; -} - -static RigNode *newRigNode(RigGraph *rg, float p[3]) -{ - RigNode *node; - node = MEM_callocN(sizeof(RigNode), "rig node"); - BLI_addtail(&rg->nodes, node); - - copy_v3_v3(node->p, p); - node->degree = 0; - node->arcs = NULL; - - return node; -} - -static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3]) -{ - RigNode *node = newRigNode(rg, p); - - node->degree = 1; - arc->tail = node; - - return node; -} - -static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge) -{ - BLI_addtail(&arc->edges, edge); - - if (edge->prev == NULL) { - copy_v3_v3(edge->head, arc->head->p); - } - else { - RigEdge *last_edge = edge->prev; - copy_v3_v3(edge->head, last_edge->tail); - RIG_calculateEdgeAngles(last_edge, edge); - } - - edge->length = len_v3v3(edge->head, edge->tail); - - arc->length += edge->length; - - arc->count += 1; -} - -static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone) -{ - RigEdge *edge; - - edge = MEM_callocN(sizeof(RigEdge), "rig edge"); - - copy_v3_v3(edge->tail, tail); - edge->bone = bone; - - if (bone) { - getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis); - } - - RIG_appendEdgeToArc(arc, edge); -} -/************************************** CLONING TEMPLATES **********************************************/ - -static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string) -{ - int i, j; - - for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) { - if (template_name[i] == '&') { - if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') { - j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME); - i++; - } - else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') { - j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME); - i++; - } - else { - name[j] = template_name[i]; - j++; - } - } - else { - name[j] = template_name[i]; - j++; - } - } - - name[j] = '\0'; - - ED_armature_ebone_unique_name(editbones, name, NULL); -} - -static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string) -{ - RigControl *ctrl; - char name[MAXBONENAME]; - - ctrl = newRigControl(rg); - - copy_v3_v3(ctrl->head, src_ctrl->head); - copy_v3_v3(ctrl->tail, src_ctrl->tail); - copy_v3_v3(ctrl->up_axis, src_ctrl->up_axis); - copy_v3_v3(ctrl->offset, src_ctrl->offset); - - ctrl->tail_mode = src_ctrl->tail_mode; - ctrl->flag = src_ctrl->flag; - - renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string); - ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob); - ctrl->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone); - - ctrl->link = src_ctrl->link; - ctrl->link_tail = src_ctrl->link_tail; - - return ctrl; -} - -static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string) -{ - RigEdge *src_edge; - RigArc *arc; - - arc = newRigArc(rg); - - arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head); - arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail); - - arc->head->degree++; - arc->tail->degree++; - - arc->length = src_arc->length; - - arc->count = src_arc->count; - - for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) { - RigEdge *edge; - - edge = MEM_callocN(sizeof(RigEdge), "rig edge"); - - copy_v3_v3(edge->head, src_edge->head); - copy_v3_v3(edge->tail, src_edge->tail); - copy_v3_v3(edge->up_axis, src_edge->up_axis); - - edge->length = src_edge->length; - edge->angle = src_edge->angle; - edge->up_angle = src_edge->up_angle; - - if (src_edge->bone != NULL) { - char name[MAXBONENAME]; - renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string); - edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob); - edge->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone); - } - - BLI_addtail(&arc->edges, edge); - } - - return arc; -} - -static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string) -{ - GHash *ptr_hash; - RigNode *node; - RigArc *arc; - RigControl *ctrl; - RigGraph *rg; - - ptr_hash = BLI_ghash_ptr_new("cloneRigGraph gh"); - - rg = newRigGraph(); - - rg->ob = ob; - rg->editbones = editbones; - - preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */ - preEditBoneDuplicate(src->editbones); /* prime bones for duplication */ - - /* Clone nodes */ - for (node = src->nodes.first; node; node = node->next) { - RigNode *cloned_node = newRigNode(rg, node->p); - BLI_ghash_insert(ptr_hash, node, cloned_node); - } - - rg->head = BLI_ghash_lookup(ptr_hash, src->head); - - /* Clone arcs */ - for (arc = src->arcs.first; arc; arc = arc->next) { - cloneArc(rg, src, arc, ptr_hash, side_string, num_string); - } - - /* Clone controls */ - for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) { - cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string); - } - - /* Relink bones properly */ - for (arc = rg->arcs.first; arc; arc = arc->next) { - RigEdge *edge; - - for (edge = arc->edges.first; edge; edge = edge->next) { - if (edge->bone != NULL) { - EditBone *bone; - - updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob); - - if (edge->bone->parent) { - bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent); - - if (bone != NULL) { - edge->bone->parent = bone; - } - else { - /* disconnect since parent isn't cloned - * this will only happen when cloning from selected bones - * */ - edge->bone->flag &= ~BONE_CONNECTED; - } - } - } - } - } - - for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { - EditBone *bone; - - updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob); - - if (ctrl->bone->parent) { - bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent); - - if (bone != NULL) { - ctrl->bone->parent = bone; - } - else { - /* disconnect since parent isn't cloned - * this will only happen when cloning from selected bones - * */ - ctrl->bone->flag &= ~BONE_CONNECTED; - } - } - - ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link); - ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail); - } - - BLI_ghash_free(ptr_hash, NULL, NULL); - - return rg; -} - - -/*******************************************************************************************************/ - -static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second) -{ - float vec_first[3], vec_second[3]; - - sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head); - sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head); - - normalize_v3(vec_first); - normalize_v3(vec_second); - - edge_first->angle = angle_normalized_v3v3(vec_first, vec_second); - - if (edge_second->bone != NULL) { - float normal[3]; - - cross_v3_v3v3(normal, vec_first, vec_second); - normalize_v3(normal); - - edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis); - } -} - -/************************************ CONTROL BONES ****************************************************/ - -static void RIG_addControlBone(RigGraph *rg, EditBone *bone) -{ - RigControl *ctrl = newRigControl(rg); - ctrl->bone = bone; - copy_v3_v3(ctrl->head, bone->head); - copy_v3_v3(ctrl->tail, bone->tail); - getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis); - ctrl->tail_mode = TL_NONE; - - BLI_ghash_insert(rg->controls_map, bone->name, ctrl); -} - -static int RIG_parentControl(RigControl *ctrl, EditBone *link) -{ - if (link) { - float offset[3]; - int flag = 0; - - sub_v3_v3v3(offset, ctrl->bone->head, link->head); - - /* if root matches, check for direction too */ - if (dot_v3v3(offset, offset) < 0.0001f) { - float vbone[3], vparent[3]; - - flag |= RIG_CTRL_FIT_ROOT; - - sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head); - sub_v3_v3v3(vparent, link->tail, link->head); - - /* test for opposite direction */ - if (dot_v3v3(vbone, vparent) > 0) { - float nor[3]; - float len; - - cross_v3_v3v3(nor, vbone, vparent); - - len = dot_v3v3(nor, nor); - if (len < 0.0001f) { - flag |= RIG_CTRL_FIT_BONE; - } - } - } - - /* Bail out if old one is automatically better */ - if (flag < ctrl->flag) { - return 0; - } - - /* if there's already a link - * overwrite only if new link is higher in the chain */ - if (ctrl->link && flag == ctrl->flag) { - EditBone *bone = NULL; - - for (bone = ctrl->link; bone; bone = bone->parent) { - /* if link is in the chain, break and use that one */ - if (bone == link) { - break; - } - } - - /* not in chain, don't update link */ - if (bone == NULL) { - return 0; - } - } - - - ctrl->link = link; - ctrl->flag = flag; - - copy_v3_v3(ctrl->offset, offset); - - return 1; - } - - return 0; -} - -static void RIG_reconnectControlBones(RigGraph *rg) -{ - RigControl *ctrl; - bool changed = true; - - /* first pass, link to deform bones */ - for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { - bPoseChannel *pchan; - bConstraint *con; - int found = 0; - - /* DO SOME MAGIC HERE */ - for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - /* constraint targets */ - if (cti && cti->get_constraint_targets) { - int target_index; - - cti->get_constraint_targets(con, &targets); - - for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) { - if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { - /* SET bone link to bone corresponding to pchan */ - EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name); - - /* Making sure bone is in this armature */ - if (link != NULL) { - /* for pole targets, link to parent bone instead, if possible */ - if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) { - if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) { - link = link->parent; - } - } - - found = RIG_parentControl(ctrl, link); - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - - /* if not found yet, check parent */ - if (found == 0) { - if (ctrl->bone->parent) { - /* make sure parent is a deforming bone - * NULL if not - * */ - EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name); - - found = RIG_parentControl(ctrl, link); - } - - /* check if bone is not superposed on another one */ - { - RigArc *arc; - RigArc *best_arc = NULL; - EditBone *link = NULL; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - RigEdge *edge; - for (edge = arc->edges.first; edge; edge = edge->next) { - if (edge->bone) { - int fit = 0; - - fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001f; - fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001f; - - if (fit) { - /* pick the bone on the arc with the lowest symmetry level - * means you connect control to the trunk of the skeleton */ - if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) { - best_arc = arc; - link = edge->bone; - } - } - } - } - } - - found = RIG_parentControl(ctrl, link); - } - } - - /* if not found yet, check child */ - if (found == 0) { - RigArc *arc; - RigArc *best_arc = NULL; - EditBone *link = NULL; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - RigEdge *edge; - for (edge = arc->edges.first; edge; edge = edge->next) { - if (edge->bone && edge->bone->parent == ctrl->bone) { - /* pick the bone on the arc with the lowest symmetry level - * means you connect control to the trunk of the skeleton */ - if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) { - best_arc = arc; - link = edge->bone; - } - } - } - } - - found = RIG_parentControl(ctrl, link); - } - - } - - - /* second pass, make chains in control bones */ - while (changed) { - changed = false; - - for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { - /* if control is not linked yet */ - if (ctrl->link == NULL) { - bPoseChannel *pchan; - bConstraint *con; - RigControl *ctrl_parent = NULL; - RigControl *ctrl_child; - int found = 0; - - if (ctrl->bone->parent) { - ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name); - } - - /* check constraints first */ - - /* DO SOME MAGIC HERE */ - for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { - /* SET bone link to ctrl corresponding to pchan */ - RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name); - - /* if owner is a control bone, link with it */ - if (link && link->link) { - RIG_parentControl(ctrl, link->bone); - found = 1; - break; - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - - if (found == 0) { - /* check if parent is already linked */ - if (ctrl_parent && ctrl_parent->link) { - RIG_parentControl(ctrl, ctrl_parent->bone); - changed = true; - } - else { - /* check childs */ - for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) { - /* if a child is linked, link to that one */ - if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) { - RIG_parentControl(ctrl, ctrl_child->bone); - changed = true; - break; - } - } - } - } - } - } - } - - /* third pass, link control tails */ - for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { - /* fit bone already means full match, so skip those */ - if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) { - GHashIterator ghi; - - /* look on deform bones first */ - BLI_ghashIterator_init(&ghi, rg->bones_map); - - for (; !BLI_ghashIterator_done(&ghi); BLI_ghashIterator_step(&ghi)) { - EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi); - - /* don't link with parent */ - if (bone->parent != ctrl->bone) { - if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01f) { - ctrl->tail_mode = TL_HEAD; - ctrl->link_tail = bone; - break; - } - else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01f) { - ctrl->tail_mode = TL_TAIL; - ctrl->link_tail = bone; - break; - } - } - } - - /* if we haven't found one yet, look in control bones */ - if (ctrl->tail_mode == TL_NONE) { - /* pass */ - } - } - } - -} - -/*******************************************************************************************************/ - -static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2) -{ - RigEdge *edge, *next_edge; - - /* ignore cases where joint is at start or end */ - if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) { - return; - } - - /* swap arcs to make sure arc1 is before arc2 */ - if (joined_arc1->head == joined_arc2->tail) { - RigArc *tmp = joined_arc1; - joined_arc1 = joined_arc2; - joined_arc2 = tmp; - } - - for (edge = joined_arc2->edges.first; edge; edge = next_edge) { - next_edge = edge->next; - - RIG_appendEdgeToArc(joined_arc1, edge); - } - - joined_arc1->tail = joined_arc2->tail; - - BLI_listbase_clear(&joined_arc2->edges); - - BLI_removeArc((BGraph *)rg, (BArc *)joined_arc2); - - BLI_removeNode((BGraph *)rg, (BNode *)node); -} - -static void RIG_removeNormalNodes(RigGraph *rg) -{ - RigNode *node, *next_node; - - for (node = rg->nodes.first; node; node = next_node) { - next_node = node->next; - - if (node->degree == 2) { - RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - if (arc->head == node || arc->tail == node) { - if (joined_arc1 == NULL) { - joined_arc1 = arc; - } - else { - joined_arc2 = arc; - break; - } - } - } - - RIG_joinArcs(rg, node, joined_arc1, joined_arc2); - } - } -} - -static void RIG_removeUneededOffsets(RigGraph *rg) -{ - RigArc *arc; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - RigEdge *first_edge, *last_edge; - - first_edge = arc->edges.first; - last_edge = arc->edges.last; - - if (first_edge->bone == NULL) { - if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001f) { - BLI_remlink(&arc->edges, first_edge); - MEM_freeN(first_edge); - } - else if (arc->head->degree == 1) { - RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001f); - - if (new_node) { - BLI_remlink(&arc->edges, first_edge); - MEM_freeN(first_edge); - BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head); - } - else { - RigEdge *next_edge = first_edge->next; - - if (next_edge) { - BLI_remlink(&arc->edges, first_edge); - MEM_freeN(first_edge); - - copy_v3_v3(arc->head->p, next_edge->head); - } - } - } - else { - /* check if all arc connected start with a null edge */ - RigArc *other_arc; - for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { - if (other_arc != arc) { - RigEdge *test_edge; - if (other_arc->head == arc->head) { - test_edge = other_arc->edges.first; - - if (test_edge->bone != NULL) { - break; - } - } - else if (other_arc->tail == arc->head) { - test_edge = other_arc->edges.last; - - if (test_edge->bone != NULL) { - break; - } - } - } - } - - if (other_arc == NULL) { - RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001); - - if (new_node) { - /* remove null edge in other arcs too */ - for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { - if (other_arc != arc) { - RigEdge *test_edge; - if (other_arc->head == arc->head) { - BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->head); - test_edge = other_arc->edges.first; - BLI_remlink(&other_arc->edges, test_edge); - MEM_freeN(test_edge); - } - else if (other_arc->tail == arc->head) { - BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->tail); - test_edge = other_arc->edges.last; - BLI_remlink(&other_arc->edges, test_edge); - MEM_freeN(test_edge); - } - } - } - - BLI_remlink(&arc->edges, first_edge); - MEM_freeN(first_edge); - BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head); - } - else { - RigEdge *next_edge = first_edge->next; - - if (next_edge) { - BLI_remlink(&arc->edges, first_edge); - MEM_freeN(first_edge); - - copy_v3_v3(arc->head->p, next_edge->head); - - /* remove null edge in other arcs too */ - for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { - if (other_arc != arc) { - RigEdge *test_edge; - if (other_arc->head == arc->head) { - test_edge = other_arc->edges.first; - BLI_remlink(&other_arc->edges, test_edge); - MEM_freeN(test_edge); - } - else if (other_arc->tail == arc->head) { - test_edge = other_arc->edges.last; - BLI_remlink(&other_arc->edges, test_edge); - MEM_freeN(test_edge); - } - } - } - } - } - } - } - } - - if (last_edge->bone == NULL) { - if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001f) { - BLI_remlink(&arc->edges, last_edge); - MEM_freeN(last_edge); - } - else if (arc->tail->degree == 1) { - RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, last_edge->head, 0.001f); - - if (new_node) { - RigEdge *previous_edge = last_edge->prev; - - BLI_remlink(&arc->edges, last_edge); - MEM_freeN(last_edge); - BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->tail); - - /* set previous angle to 0, since there's no following edges */ - if (previous_edge) { - previous_edge->angle = 0; - } - } - else { - RigEdge *previous_edge = last_edge->prev; - - if (previous_edge) { - BLI_remlink(&arc->edges, last_edge); - MEM_freeN(last_edge); - - copy_v3_v3(arc->tail->p, previous_edge->tail); - previous_edge->angle = 0; - } - } - } - } - } -} - -static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, bool selected) -{ - EditBone *bone, *last_bone = root_bone; - RigArc *arc = NULL; - int contain_head = 0; - - for (bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) { - int nb_children; - - if (selected == 0 || (bone->flag & BONE_SELECTED)) { - if ((bone->flag & BONE_NO_DEFORM) == 0) { - BLI_ghash_insert(rg->bones_map, bone->name, bone); - - if (arc == NULL) { - arc = newRigArc(rg); - - if (starting_node == NULL) { - starting_node = newRigNodeHead(rg, arc, root_bone->head); - } - else { - addRigNodeHead(rg, arc, starting_node); - } - } - - if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) { - RIG_addEdgeToArc(arc, bone->head, NULL); - } - - RIG_addEdgeToArc(arc, bone->tail, bone); - - last_bone = bone; - - if (STREQ(bone->name, "head")) { - contain_head = 1; - } - } - else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) { /* ignore locked bones */ - RIG_addControlBone(rg, bone); - } - } - - nb_children = countEditBoneChildren(list, bone); - if (nb_children > 1) { - RigNode *end_node = NULL; - int i; - - if (arc != NULL) { - end_node = newRigNodeTail(rg, arc, bone->tail); - } - else { - end_node = newRigNode(rg, bone->tail); - } - - for (i = 0; i < nb_children; i++) { - root_bone = nextEditBoneChild(list, bone, i); - RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected); - } - - /* arc ends here, break */ - break; - } - } - - /* If the loop exited without forking */ - if (arc != NULL && bone == NULL) { - newRigNodeTail(rg, arc, last_bone->tail); - } - - if (contain_head) { - rg->head = arc->tail; - } -} - -/*******************************************************************************************************/ -static void RIG_findHead(RigGraph *rg) -{ - if (rg->head == NULL) { - if (BLI_listbase_is_single(&rg->arcs)) { - RigArc *arc = rg->arcs.first; - - rg->head = (RigNode *)arc->head; - } - else { - RigArc *arc; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - RigEdge *edge = arc->edges.last; - - if (edge->bone->flag & (BONE_TIPSEL | BONE_SELECTED)) { - rg->head = arc->tail; - break; - } - } - } - - if (rg->head == NULL) { - rg->head = rg->nodes.first; - } - } -} - -/*******************************************************************************************************/ - -static void RIG_printNode(RigNode *node, const char name[]) -{ - printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]); - - if (node->symmetry_flag & SYM_TOPOLOGICAL) { - if (node->symmetry_flag & SYM_AXIAL) - printf("Symmetry AXIAL\n"); - else if (node->symmetry_flag & SYM_RADIAL) - printf("Symmetry RADIAL\n"); - - print_v3("symmetry axis", node->symmetry_axis); - } -} - -void RIG_printArcBones(RigArc *arc) -{ - RigEdge *edge; - - for (edge = arc->edges.first; edge; edge = edge->next) { - if (edge->bone) - printf("%s ", edge->bone->name); - else - printf("---- "); - } - printf("\n"); -} - -static void RIG_printCtrl(RigControl *ctrl, char *indent) -{ - char text[128]; - - printf("%sBone: %s\n", indent, ctrl->bone->name); - printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!"); - - BLI_snprintf(text, sizeof(text), "%soffset", indent); - print_v3(text, ctrl->offset); - - printf("%sFlag: %i\n", indent, ctrl->flag); -} - -static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs) -{ - RigControl *ctrl; - char indent[64]; - char *s = indent; - int i; - - for (i = 0; i < tabs; i++) { - s[0] = '\t'; - s++; - } - s[0] = 0; - - for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { - if (ctrl->link == bone) { - RIG_printCtrl(ctrl, indent); - RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1); - } - } -} - -void RIG_printArc(RigGraph *rg, RigArc *arc) -{ - RigEdge *edge; - - RIG_printNode((RigNode *)arc->head, "head"); - - for (edge = arc->edges.first; edge; edge = edge->next) { - printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]); - printf("\t\tlength %f\n", edge->length); - printf("\t\tangle %f\n", edge->angle * (float)(180 / M_PI)); - if (edge->bone) { - printf("\t\t%s\n", edge->bone->name); - RIG_printLinkedCtrl(rg, edge->bone, 3); - } - } - printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); - - RIG_printNode((RigNode *)arc->tail, "tail"); -} - -void RIG_printGraph(RigGraph *rg) -{ - RigArc *arc; - - printf("---- ARCS ----\n"); - for (arc = rg->arcs.first; arc; arc = arc->next) { - RIG_printArc(rg, arc); - printf("\n"); - } - - if (rg->head) { - RIG_printNode(rg->head, "HEAD NODE:"); - } - else { - printf("HEAD NODE: NONE\n"); - } -} - -/*******************************************************************************************************/ - -RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm) -{ - Object *obedit = CTX_data_edit_object(C); - Scene *scene = CTX_data_scene(C); - EditBone *ebone; - RigGraph *rg; - - rg = newRigGraph(); - - if (obedit == ob) { - rg->editbones = ((bArmature *)obedit->data)->edbo; - } - else { - rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); - make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); - rg->flag |= RIG_FREE_BONELIST; - } - - rg->ob = ob; - - /* Do the rotations */ - for (ebone = rg->editbones->first; ebone; ebone = ebone->next) { - if (ebone->parent == NULL) { - RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0); - } - } - - BLI_removeDoubleNodes((BGraph *)rg, 0.001); - - RIG_removeNormalNodes(rg); - - RIG_removeUneededOffsets(rg); - - BLI_buildAdjacencyList((BGraph *)rg); - - RIG_findHead(rg); - - BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit); - - RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ - - if (BLI_isGraphCyclic((BGraph *)rg)) { - printf("armature cyclic\n"); - } - - return rg; -} - -static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm) -{ - Object *obedit = CTX_data_edit_object(C); - Scene *scene = CTX_data_scene(C); - EditBone *ebone; - RigGraph *rg; - - rg = newRigGraph(); - - if (obedit == ob) { - rg->editbones = arm->edbo; - } - else { - rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); - make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); - rg->flag |= RIG_FREE_BONELIST; - } - - rg->ob = ob; - - /* Do the rotations */ - for (ebone = rg->editbones->first; ebone; ebone = ebone->next) { - if (ebone->parent == NULL) { - RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1); - } - } - - BLI_removeDoubleNodes((BGraph *)rg, 0.001); - - RIG_removeNormalNodes(rg); - - RIG_removeUneededOffsets(rg); - - BLI_buildAdjacencyList((BGraph *)rg); - - RIG_findHead(rg); - - BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit); - - RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ - - if (BLI_isGraphCyclic((BGraph *)rg)) { - printf("armature cyclic\n"); - } - - return rg; -} -/************************************ GENERATING *****************************************************/ - -#if 0 -static EditBone *add_editbonetolist(char *name, ListBase *list) -{ - EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone"); - - BLI_strncpy(bone->name, name, sizeof(bone->name)); - ED_armature_ebone_unique_name(list, bone->name, NULL); - - BLI_addtail(list, bone); - - bone->flag |= BONE_TIPSEL; - bone->weight = 1.0F; - bone->dist = 0.25F; - bone->xwidth = 0.1; - bone->zwidth = 0.1; - bone->rad_head = 0.10; - bone->rad_tail = 0.05; - bone->segments = 1; - bone->layer = 1; //arm->layer; - - /* Bendy-Bone parameters */ - bone->roll1 = 0.0f; - bone->roll2 = 0.0f; - bone->curveInX = 0.0f; - bone->curveInY = 0.0f; - bone->curveOutX = 0.0f; - bone->curveOutY = 0.0f; - bone->ease1 = 1.0f; - bone->ease2 = 1.0f; - bone->scaleIn = 1.0f; - bone->scaleOut = 1.0f; - - return bone; -} -#endif - -#if 0 /* UNUSED */ -static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit) -{ - while (node->multi_level > multi_level_limit && node->link_up) - { - node = node->link_up; - } - - while (node->multi_level < multi_level_limit && node->link_down) - { - node = node->link_down; - } - - if (node->multi_level == multi_level_limit) - { - int i; - - for (i = 0; i < node->degree; i++) - { - ReebArc *earc = node->arcs[i]; - - if (earc->flag == ARC_FREE && earc->head == node) - { - ReebNode *other = BIF_otherNodeFromIndex(earc, node); - - earc->flag = ARC_USED; - - //generateBonesForArc(rigg, earc, node, other); - generateMissingArcsFromNode(rigg, other, multi_level_limit); - } - } - } -} - -static void generateMissingArcs(RigGraph *rigg) -{ - ReebGraph *reebg; - int multi_level_limit = 5; - - for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up) - { - ReebArc *earc; - - for (earc = reebg->arcs.first; earc; earc = earc->next) - { - if (earc->flag == ARC_USED) - { - generateMissingArcsFromNode(rigg, earc->head, multi_level_limit); - generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit); - } - } - } -} -#endif - -/************************************ RETARGETTING *****************************************************/ - -static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize); - -static void repositionTailControl(RigGraph *rigg, RigControl *ctrl); - -static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize) -{ - if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) { - RigControl *ctrl_child; - -#if 0 - printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name); - - if (ctrl->link_tail) - { - printf(" TAIL: %s", ctrl->link_tail->name); - } - - printf("\n"); -#endif - - /* if there was a tail link: apply link, recalc resize factor and qrot */ - if (ctrl->tail_mode != TL_NONE) { - float *tail_vec = NULL; - float v1[3], v2[3], qtail[4]; - - if (ctrl->tail_mode == TL_TAIL) { - tail_vec = ctrl->link_tail->tail; - } - else if (ctrl->tail_mode == TL_HEAD) { - tail_vec = ctrl->link_tail->head; - } - - sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head); - sub_v3_v3v3(v2, tail_vec, ctrl->bone->head); - - copy_v3_v3(ctrl->bone->tail, tail_vec); - - rotation_between_vecs_to_quat(qtail, v1, v2); - mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot); - - resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail); - } - - ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot); - - /* Cascade to connected control bones */ - for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) { - if (ctrl_child->link == ctrl->bone) { - repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize); - } - if (ctrl_child->link_tail == ctrl->bone) { - repositionTailControl(rigg, ctrl_child); - } - } - } -} - -static void repositionTailControl(RigGraph *rigg, RigControl *ctrl) -{ - ctrl->flag |= RIG_CTRL_TAIL_DONE; - - finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */ -} - -static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize) -{ - float parent_offset[3], tail_offset[3]; - - copy_v3_v3(parent_offset, ctrl->offset); - mul_v3_fl(parent_offset, resize); - mul_qt_v3(qrot, parent_offset); - - add_v3_v3v3(ctrl->bone->head, head, parent_offset); - - ctrl->flag |= RIG_CTRL_HEAD_DONE; - - copy_qt_qt(ctrl->qrot, qrot); - - if (ctrl->tail_mode == TL_NONE) { - sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head); - mul_v3_fl(tail_offset, resize); - mul_qt_v3(qrot, tail_offset); - - add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset); - - ctrl->flag |= RIG_CTRL_TAIL_DONE; - } - - finalizeControl(rigg, ctrl, resize); -} - -static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3]) -{ - Scene *scene = CTX_data_scene(C); - EditBone *bone; - RigControl *ctrl; - float qrot[4], resize; - float v1[3], v2[3]; - float l1, l2; - - bone = edge->bone; - - sub_v3_v3v3(v1, edge->tail, edge->head); - sub_v3_v3v3(v2, vec1, vec0); - - l1 = normalize_v3(v1); - l2 = normalize_v3(v2); - - resize = l2 / l1; - - rotation_between_vecs_to_quat(qrot, v1, v2); - - copy_v3_v3(bone->head, vec0); - copy_v3_v3(bone->tail, vec1); - - if (!is_zero_v3(up_axis)) { - float qroll[4]; - - if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) { - bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis); - } - else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) { - bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis); - } - else { - unit_qt(qroll); - } - - mul_qt_qtqt(qrot, qroll, qrot); - } - else { - bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot); - } - - for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) { - if (ctrl->link == bone) { - repositionControl(rigg, ctrl, vec0, vec1, qrot, resize); - } - if (ctrl->link_tail == bone) { - repositionTailControl(rigg, ctrl); - } - } -} - -static RetargetMode detectArcRetargetMode(RigArc *arc); -static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start); - - -static RetargetMode detectArcRetargetMode(RigArc *iarc) -{ - RetargetMode mode = RETARGET_AGGRESSIVE; - ReebArc *earc = iarc->link_mesh; - RigEdge *edge; - int large_angle = 0; - float avg_angle = 0; - /* float avg_length = 0; */ /* UNUSED */ - int nb_edges = 0; - - - for (edge = iarc->edges.first; edge; edge = edge->next) { - avg_angle += edge->angle; - nb_edges++; - } - - avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */ - - /* avg_length = iarc->length / nb_edges; */ /* UNUSED */ - - - if (nb_edges > 2) { - for (edge = iarc->edges.first; edge; edge = edge->next) { - if (fabsf(edge->angle - avg_angle) > (float)(M_PI / 6)) { - large_angle = 1; - } - } - } - else if (nb_edges == 2 && avg_angle > 0) { - large_angle = 1; - } - - - if (large_angle == 0) { - mode = RETARGET_LENGTH; - } - - if (earc->bcount <= (iarc->count - 1)) { - mode = RETARGET_LENGTH; - } - - return mode; -} - -#ifndef USE_THREADS -static void printMovesNeeded(int *positions, int nb_positions) -{ - int moves = 0; - int i; - - for (i = 0; i < nb_positions; i++) { - moves += positions[i] - (i + 1); - } - - printf("%i moves needed\n", moves); -} - -static void printPositions(int *positions, int nb_positions) -{ - int i; - - for (i = 0; i < nb_positions; i++) { - printf("%i ", positions[i]); - } - printf("\n"); -} -#endif - -#define MAX_COST FLT_MAX /* FIX ME */ - -static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight) -{ - EmbedBucket *bucket = NULL; - float max_dist = 0; - float v1[3], v2[3], c[3]; - float v1_inpf; - - if (distance_weight > 0) { - sub_v3_v3v3(v1, vec0, vec1); - - v1_inpf = dot_v3v3(v1, v1); - - if (v1_inpf > 0) { - int j; - for (j = i0 + 1; j < i1 - 1; j++) { - float dist; - - bucket = IT_peek(iter, j); - - sub_v3_v3v3(v2, bucket->p, vec1); - - cross_v3_v3v3(c, v1, v2); - - dist = dot_v3v3(c, c) / v1_inpf; - - max_dist = dist > max_dist ? dist : max_dist; - } - - return distance_weight * max_dist; - } - else { - return MAX_COST; - } - } - else { - return 0; - } -} - -static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight) -{ - if (angle_weight > 0) { - float current_angle; - - if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) { - current_angle = saacos(dot_v3v3(vec_first, vec_second)); - - return angle_weight * fabsf(current_angle - original_angle); - } - else { - return angle_weight * (float)M_PI; - } - } - else { - return 0; - } -} - -static float costLength(float original_length, float current_length, float length_weight) -{ - if (current_length == 0) { - return MAX_COST; - } - else { - float length_ratio = fabsf((current_length - original_length) / original_length); - return length_weight * length_ratio * length_ratio; - } -} - -#if 0 -static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2) -{ - float vec[3]; - float length; - - sub_v3_v3v3(vec, vec2, vec1); - length = normalize_v3(vec); - - return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2); -} -#endif - -static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, - float *vec0, float *vec1, float *vec2, int i1, int i2, - float angle_weight, float length_weight, float distance_weight) -{ - float vec_second[3], vec_first[3]; - float length2; - float new_cost = 0; - - sub_v3_v3v3(vec_second, vec2, vec1); - length2 = normalize_v3(vec_second); - - - /* Angle cost */ - if (edge->prev) { - sub_v3_v3v3(vec_first, vec1, vec0); - normalize_v3(vec_first); - - new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight); - } - - /* Length cost */ - new_cost += costLength(edge->length, length2, length_weight); - - /* Distance cost */ - new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight); - - return new_cost; -} - -static int indexMemoNode(int nb_positions, int previous, int current, int joints_left) -{ - return joints_left * nb_positions * nb_positions + current * nb_positions + previous; -} - -static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left) -{ - int previous = 0, current = 0; - int i = 0; - - for (i = 0; joints_left > 0; joints_left--, i++) { - MemoNode *node; - node = table + indexMemoNode(nb_positions, previous, current, joints_left); - - positions[i] = node->next; - - previous = current; - current = node->next; - } -} - -static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, - int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, - int joints_left, float angle_weight, float length_weight, float distance_weight) -{ - MemoNode *node; - int index = indexMemoNode(nb_positions, previous, current, joints_left); - - node = table + index; - - if (node->weight != 0) { - return node; - } - else if (joints_left == 0) { - float *vec0 = vec_cache[previous]; - float *vec1 = vec_cache[current]; - float *vec2 = vec_cache[nb_positions + 1]; - - node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight); - - return node; - } - else { - MemoNode *min_node = NULL; - float *vec0 = vec_cache[previous]; - float *vec1 = vec_cache[current]; - float min_weight = 0.0f; - int min_next = 0; - int next; - - for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) { - MemoNode *next_node; - float *vec2 = vec_cache[next]; - float weight = 0.0f; - - /* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */ - weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight); - - if (weight >= MAX_COST) { - continue; - } - - /* add node weight */ - next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight); - weight += next_node->weight; - - if (min_node == NULL || weight < min_weight) { - min_weight = weight; - min_node = next_node; - min_next = next; - } - } - - if (min_node) { - node->weight = min_weight; - node->next = min_next; - return node; - } - else { - node->weight = MAX_COST; - return node; - } - } - -} - -static int testFlipArc(RigArc *iarc, RigNode *inode_start) -{ - ReebArc *earc = iarc->link_mesh; - ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh); - - /* no flip needed if both nodes are the same */ - if ((enode_start == earc->head && inode_start == iarc->head) || - (enode_start == earc->tail && inode_start == iarc->tail)) - { - return 0; - } - else { - return 1; - } -} - -static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) -{ - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - RigEdge *edge; - ReebNode *node_start, *node_end; - ReebArc *earc = iarc->link_mesh; - float angle_weight = 1.0; // GET FROM CONTEXT - float length_weight = 1.0; - float distance_weight = 1.0; -#ifndef USE_THREADS - float min_cost = FLT_MAX; -#endif - float *vec0, *vec1; - int *best_positions; - int nb_edges = BLI_listbase_count(&iarc->edges); - int nb_joints = nb_edges - 1; - RetargetMethod method = METHOD_MEMOIZE; - int i; - - if (nb_joints > earc->bcount) { - printf("NOT ENOUGH BUCKETS!\n"); - return; - } - - best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions"); - - if (testFlipArc(iarc, inode_start)) { - node_start = earc->tail; - node_end = earc->head; - } - else { - node_start = earc->head; - node_end = earc->tail; - } - - /* equal number of joints and potential position, just fill them in */ - if (nb_joints == earc->bcount) { - /* init with first values */ - for (i = 0; i < nb_joints; i++) { - best_positions[i] = i + 1; - } - } - if (method == METHOD_MEMOIZE) { - int nb_positions = earc->bcount; - int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1); - MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table"); -#ifndef USE_THREADS - MemoNode *result; -#endif - float **positions_cache = MEM_callocN(sizeof(float *) * (nb_positions + 2), "positions cache"); - - positions_cache[0] = node_start->p; - positions_cache[nb_positions + 1] = node_end->p; - - initArcIterator(iter, earc, node_start); - - for (i = 1; i <= nb_positions; i++) { - EmbedBucket *bucket = IT_peek(iter, i); - positions_cache[i] = bucket->p; - } - -#ifndef USE_THREADS - result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight); - min_cost = result->weight; -#else - solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight); -#endif - - copyMemoPositions(best_positions, table, earc->bcount, nb_joints); - - MEM_freeN(table); - MEM_freeN(positions_cache); - } - - vec0 = node_start->p; - initArcIterator(iter, earc, node_start); - -#ifndef USE_THREADS - printPositions(best_positions, nb_joints); - printMovesNeeded(best_positions, nb_joints); - printf("min_cost %f\n", min_cost); - printf("buckets: %i\n", earc->bcount); -#endif - - /* set joints to best position */ - for (edge = iarc->edges.first, i = 0; - edge; - edge = edge->next, i++) - { - float *no = NULL; - if (i < nb_joints) { - EmbedBucket *bucket = IT_peek(iter, best_positions[i]); - vec1 = bucket->p; - no = bucket->no; - } - else { - vec1 = node_end->p; - no = node_end->no; - } - - if (edge->bone) { - repositionBone(C, rigg, edge, vec0, vec1, no); - } - - vec0 = vec1; - } - - MEM_freeN(best_positions); -} - -static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) -{ - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - ReebArc *earc = iarc->link_mesh; - ReebNode *node_start, *node_end; - RigEdge *edge; - EmbedBucket *bucket = NULL; - float embedding_length = 0; - float *vec0 = NULL; - float *vec1 = NULL; - float *previous_vec = NULL; - - - if (testFlipArc(iarc, inode_start)) { - node_start = (ReebNode *)earc->tail; - node_end = (ReebNode *)earc->head; - } - else { - node_start = (ReebNode *)earc->head; - node_end = (ReebNode *)earc->tail; - } - - initArcIterator(iter, earc, node_start); - - bucket = IT_next(iter); - - vec0 = node_start->p; - - while (bucket != NULL) { - vec1 = bucket->p; - - embedding_length += len_v3v3(vec0, vec1); - - vec0 = vec1; - bucket = IT_next(iter); - } - - embedding_length += len_v3v3(node_end->p, vec1); - - /* fit bones */ - initArcIterator(iter, earc, node_start); - - bucket = IT_next(iter); - - vec0 = node_start->p; - previous_vec = vec0; - vec1 = bucket->p; - - for (edge = iarc->edges.first; edge; edge = edge->next) { - float new_bone_length = edge->length / iarc->length * embedding_length; - float *no = NULL; - float length = 0; - - while (bucket && new_bone_length > length) { - length += len_v3v3(previous_vec, vec1); - bucket = IT_next(iter); - previous_vec = vec1; - vec1 = bucket->p; - no = bucket->no; - } - - if (bucket == NULL) { - vec1 = node_end->p; - no = node_end->no; - } - - /* no need to move virtual edges (space between unconnected bones) */ - if (edge->bone) { - repositionBone(C, rigg, edge, vec0, vec1, no); - } - - vec0 = vec1; - previous_vec = vec1; - } -} - -static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) -{ - RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam"); - - p->rigg = rigg; - p->iarc = iarc; - p->inode_start = inode_start; - p->context = C; - - BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH); -} - -void exec_retargetArctoArc(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) -{ - RetargetParam *p = (RetargetParam *)taskdata; - RigGraph *rigg = p->rigg; - RigArc *iarc = p->iarc; - bContext *C = p->context; - RigNode *inode_start = p->inode_start; - ReebArc *earc = iarc->link_mesh; - - if (BLI_listbase_is_single(&iarc->edges)) { - RigEdge *edge = iarc->edges.first; - - if (testFlipArc(iarc, inode_start)) { - repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no); - } - else { - repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no); - } - } - else { - RetargetMode mode = detectArcRetargetMode(iarc); - - if (mode == RETARGET_AGGRESSIVE) { - retargetArctoArcAggresive(C, rigg, iarc, inode_start); - } - else { - retargetArctoArcLength(C, rigg, iarc, inode_start); - } - } -} - -static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node) -{ - ReebNode *enode = top_node; - ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); - int ishape, eshape; - - ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS; - eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; - - inode->link_mesh = enode; - - while (ishape == eshape && enode->link_down) { - inode->link_mesh = enode; - - enode = enode->link_down; - reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */ - eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; - } -} - -static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode) -{ - int i; - - for (i = 0; i < enode->degree; i++) { - ReebArc *earc = (ReebArc *)enode->arcs[i]; - - if (earc->flag == ARC_FREE) { - earc->flag = ARC_TAKEN; - - if (earc->tail->degree > 1 && earc->tail != end_enode) { - markMultiResolutionChildArc(end_enode, earc->tail); - } - break; - } - } -} - -static void markMultiResolutionArc(ReebArc *start_earc) -{ - if (start_earc->link_up) { - ReebArc *earc; - for (earc = start_earc->link_up; earc; earc = earc->link_up) { - earc->flag = ARC_TAKEN; - - if (earc->tail->index != start_earc->tail->index) { - markMultiResolutionChildArc(earc->tail, earc->tail); - } - } - } -} - -static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc) -{ - ReebNode *enode = next_earc->head; - ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); - int ishape, eshape; - - ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)start_node, (BArc *)next_iarc, 1) % SHAPE_LEVELS; - eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS; - - while (ishape != eshape && next_earc->link_up) { - next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels - - next_earc = next_earc->link_up; - reebg = reebg->link_up; - enode = next_earc->head; - eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS; - } - - next_earc->flag = ARC_USED; - next_iarc->link_mesh = next_earc; - - /* mark all higher levels as taken too */ - markMultiResolutionArc(next_earc); -// while (next_earc->link_up) -// { -// next_earc = next_earc->link_up; -// next_earc->flag = ARC_TAKEN; -// } -} - -static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode) -{ - ReebNode *enode; - int ishape, eshape; - - enode = reebg->nodes.first; - - ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS; - eshape = BLI_subtreeShape((BGraph *)rigg->link_mesh, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; - - while (ishape != eshape && reebg->link_up) { - reebg = reebg->link_up; - - enode = reebg->nodes.first; - - eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; - } - - inode->link_mesh = enode; -} - -static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root) -{ - ReebNode *enode = start_node->link_mesh; - ReebArc *next_earc; - int symmetry_level = next_iarc->symmetry_level; - int symmetry_group = next_iarc->symmetry_group; - int symmetry_flag = next_iarc->symmetry_flag; - int i; - - next_iarc->link_mesh = NULL; - -// if (root) -// { -// printf("-----------------------\n"); -// printf("MATCHING LIMB\n"); -// RIG_printArcBones(next_iarc); -// } - - for (i = 0; i < enode->degree; i++) { - next_earc = (ReebArc *)enode->arcs[i]; - -// if (next_earc->flag == ARC_FREE) -// { -// printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n", -// symmetry_level, next_earc->symmetry_level, -// symmetry_flag, next_earc->symmetry_flag, -// symmetry_group, next_earc->symmetry_flag); -// } - - if (next_earc->flag == ARC_FREE && - next_earc->symmetry_flag == symmetry_flag && - next_earc->symmetry_group == symmetry_group && - next_earc->symmetry_level == symmetry_level) - { -// printf("CORRESPONDING ARC FOUND\n"); -// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); - - matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); - break; - } - } - - /* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */ - if (next_iarc->link_mesh == NULL) { -// printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n"); - - if (enode->link_up) { - start_node->link_mesh = enode->link_up; - findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0); - } - } - - /* still not found, print debug info */ - if (root && next_iarc->link_mesh == NULL) { - start_node->link_mesh = enode; /* linking back with root node */ - -// printf("NO CORRESPONDING ARC FOUND\n"); -// RIG_printArcBones(next_iarc); -// -// printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level); -// -// printf("LOOKING FOR\n"); -// printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group); -// -// printf("CANDIDATES\n"); -// for (i = 0; i < enode->degree; i++) -// { -// next_earc = (ReebArc *)enode->arcs[i]; -// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); -// } - - /* Emergency matching */ - for (i = 0; i < enode->degree; i++) { - next_earc = (ReebArc *)enode->arcs[i]; - - if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) { -// printf("USING:\n"); -// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); - matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); - break; - } - } - } - -} - -static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node) -{ - RigNode *inode = start_node; - int i; - - /* no start arc on first node */ - if (start_arc) { - ReebNode *enode = start_node->link_mesh; - ReebArc *earc = start_arc->link_mesh; - - retargetArctoArc(C, rigg, start_arc, start_node); - - enode = BIF_otherNodeFromIndex(earc, enode); - inode = (RigNode *)BLI_otherNode((BArc *)start_arc, (BNode *)inode); - - /* match with lowest node with correct shape */ - matchMultiResolutionNode(rigg, inode, enode); - } - - for (i = 0; i < inode->degree; i++) { - RigArc *next_iarc = (RigArc *)inode->arcs[i]; - - /* no back tracking */ - if (next_iarc != start_arc) { - findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1); - if (next_iarc->link_mesh) { - retargetSubgraph(C, rigg, next_iarc, inode); - } - } - } -} - -static void finishRetarget(RigGraph *rigg) -{ - BLI_task_pool_work_and_wait(rigg->task_pool); -} - -static void adjustGraphs(bContext *C, RigGraph *rigg) -{ - bArmature *arm = rigg->ob->data; - RigArc *arc; - - for (arc = rigg->arcs.first; arc; arc = arc->next) { - if (arc->link_mesh) { - retargetArctoArc(C, rigg, arc, arc->head); - } - } - - finishRetarget(rigg); - - /* Turn the list into an armature */ - arm->edbo = rigg->editbones; - ED_armature_from_edit(arm); - - ED_undo_push(C, "Retarget Skeleton"); -} - -static void retargetGraphs(bContext *C, RigGraph *rigg) -{ - bArmature *arm = rigg->ob->data; - ReebGraph *reebg = rigg->link_mesh; - RigNode *inode; - - /* flag all ReebArcs as free */ - BIF_flagMultiArcs(reebg, ARC_FREE); - - /* return to first level */ - inode = rigg->head; - - matchMultiResolutionStartingNode(rigg, reebg, inode); - - retargetSubgraph(C, rigg, NULL, inode); - - //generateMissingArcs(rigg); - - finishRetarget(rigg); - - /* Turn the list into an armature */ - arm->edbo = rigg->editbones; - ED_armature_from_edit(arm); -} - -const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index) -{ - RigArc *arc = BLI_findlink(&rg->arcs, arc_index); - RigEdge *iedge; - - if (arc == NULL) { - return "None"; - } - - if (bone_index == BLI_listbase_count(&arc->edges)) { - return "Last joint"; - } - - iedge = BLI_findlink(&arc->edges, bone_index); - - if (iedge == NULL) { - return "Done"; - } - - if (iedge->bone == NULL) { - return "Bone offset"; - } - - return iedge->bone->name; -} - -int RIG_nbJoints(RigGraph *rg) -{ - RigArc *arc; - int total = 0; - - total += BLI_listbase_count(&rg->nodes); - - for (arc = rg->arcs.first; arc; arc = arc->next) { - total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */ - } - - return total; -} - -static void BIF_freeRetarget(void) -{ - if (GLOBAL_RIGG) { - RIG_freeRigGraph((BGraph *)GLOBAL_RIGG); - GLOBAL_RIGG = NULL; - } -} - -void BIF_retargetArmature(bContext *C) -{ - ReebGraph *reebg; - double start_time, end_time; - double gstart_time, gend_time; - double reeb_time, rig_time = 0.0, retarget_time = 0.0, total_time; - - gstart_time = start_time = PIL_check_seconds_timer(); - - reebg = BIF_ReebGraphMultiFromEditMesh(C); - - end_time = PIL_check_seconds_timer(); - reeb_time = end_time - start_time; - - printf("Reeb Graph created\n"); - - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - Object *ob = base->object; - - if (ob->type == OB_ARMATURE) { - RigGraph *rigg; - bArmature *arm; - - arm = ob->data; - - /* Put the armature into editmode */ - - - start_time = PIL_check_seconds_timer(); - - rigg = RIG_graphFromArmature(C, ob, arm); - - end_time = PIL_check_seconds_timer(); - rig_time = end_time - start_time; - - printf("Armature graph created\n"); - - //RIG_printGraph(rigg); - - rigg->link_mesh = reebg; - - printf("retargetting %s\n", ob->id.name); - - start_time = PIL_check_seconds_timer(); - - retargetGraphs(C, rigg); - - end_time = PIL_check_seconds_timer(); - retarget_time = end_time - start_time; - - BIF_freeRetarget(); - - GLOBAL_RIGG = rigg; - - break; /* only one armature at a time */ - } - } - CTX_DATA_END; - - - gend_time = PIL_check_seconds_timer(); - - total_time = gend_time - gstart_time; - - printf("-----------\n"); - printf("runtime: \t%.3f\n", total_time); - printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100); - printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100); - printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100); - printf("-----------\n"); - - ED_undo_push(C, "Retarget Skeleton"); - - // XXX -// allqueue(REDRAWVIEW3D, 0); -} - -void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg) -{ - Object *obedit = CTX_data_edit_object(C); - Scene *scene = CTX_data_scene(C); - bArmature *armedit = obedit->data; - Object *ob; - RigGraph *rigg; - RigArc *iarc; - char *side_string = scene->toolsettings->skgen_side_string; - char *num_string = scene->toolsettings->skgen_num_string; - int free_template = 0; - - if (template_rigg) { - ob = template_rigg->ob; - } - else { - free_template = 1; - ob = obedit; - template_rigg = armatureSelectedToGraph(C, ob, ob->data); - } - - if (BLI_listbase_is_empty(&template_rigg->arcs)) { -// XXX -// error("No Template and no deforming bones selected"); - return; - } - - rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string); - - iarc = rigg->arcs.first; - - iarc->link_mesh = earc; - iarc->head->link_mesh = earc->head; - iarc->tail->link_mesh = earc->tail; - - retargetArctoArc(C, rigg, iarc, iarc->head); - - finishRetarget(rigg); - - /* free template if it comes from the edit armature */ - if (free_template) { - RIG_freeRigGraph((BGraph *)template_rigg); - } - RIG_freeRigGraph((BGraph *)rigg); - - ED_armature_edit_validate_active(armedit); - -// XXX -// allqueue(REDRAWVIEW3D, 0); -} - -void BIF_adjustRetarget(bContext *C) -{ - if (GLOBAL_RIGG) { - adjustGraphs(C, GLOBAL_RIGG); - } -} diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c deleted file mode 100644 index 84eb780b56b..00000000000 --- a/source/blender/editors/armature/editarmature_sketch.c +++ /dev/null @@ -1,2664 +0,0 @@ -/* - * ***** 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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/armature/editarmature_sketch.c - * \ingroup edarmature - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_armature_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" - -#include "BKE_context.h" -#include "BKE_sketch.h" - -#include "RNA_define.h" -#include "RNA_access.h" - -#include "ED_view3d.h" -#include "ED_screen.h" - -#include "BIF_gl.h" -#include "ED_armature.h" -#include "armature_intern.h" -#include "BIF_retarget.h" -#include "BIF_generate.h" - -#include "ED_transform.h" -#include "ED_transform_snap_object_context.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "GPU_select.h" - -typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *); -typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *); - -typedef struct SK_GestureAction { - char name[64]; - GestureDetectFct detect; - GestureApplyFct apply; -} SK_GestureAction; - -#if 0 /* UNUSED 2.5 */ -static SK_Point boneSnap; -#endif - -static int LAST_SNAP_POINT_VALID = 0; -static float LAST_SNAP_POINT[3]; - - -typedef struct SK_StrokeIterator { - HeadFct head; - TailFct tail; - PeekFct peek; - NextFct next; - NextNFct nextN; - PreviousFct previous; - StoppedFct stopped; - - float *p, *no; - float size; - - int length; - int index; - /*********************************/ - SK_Stroke *stroke; - int start; - int end; - int stride; -} SK_StrokeIterator; - -/******************** PROTOTYPES ******************************/ - -void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end); - -int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); -void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); - -SK_Sketch *contextSketch(const bContext *c, int create); -SK_Sketch *viewcontextSketch(ViewContext *vc, int create); - -void sk_resetOverdraw(SK_Sketch *sketch); -int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk); - -/******************** GESTURE ACTIONS ******************************/ - -static SK_GestureAction GESTURE_ACTIONS[] = { - {"Cut", sk_detectCutGesture, sk_applyCutGesture}, - {"Trim", sk_detectTrimGesture, sk_applyTrimGesture}, - {"Command", sk_detectCommandGesture, sk_applyCommandGesture}, - {"Delete", sk_detectDeleteGesture, sk_applyDeleteGesture}, - {"Merge", sk_detectMergeGesture, sk_applyMergeGesture}, - {"Reverse", sk_detectReverseGesture, sk_applyReverseGesture}, - {"Convert", sk_detectConvertGesture, sk_applyConvertGesture}, - {"", NULL, NULL} -}; - -/******************** TEMPLATES UTILS *************************/ - -static char *TEMPLATES_MENU = NULL; -static int TEMPLATES_CURRENT = 0; -static GHash *TEMPLATES_HASH = NULL; -static RigGraph *TEMPLATE_RIGG = NULL; - -void BIF_makeListTemplates(const bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = CTX_data_tool_settings(C); - Base *base; - int index = 0; - - if (TEMPLATES_HASH != NULL) { - BLI_ghash_free(TEMPLATES_HASH, NULL, NULL); - } - - TEMPLATES_HASH = BLI_ghash_int_new("makeListTemplates gh"); - TEMPLATES_CURRENT = 0; - - for (base = FIRSTBASE; base; base = base->next) { - Object *ob = base->object; - - if (ob != obedit && ob->type == OB_ARMATURE) { - index++; - BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob); - - if (ob == ts->skgen_template) { - TEMPLATES_CURRENT = index; - } - } - } -} - -#if 0 /* UNUSED */ -const char *BIF_listTemplates(const bContext *UNUSED(C)) -{ - GHashIterator ghi; - const char *menu_header = IFACE_("Template %t|None %x0|"); - char *p; - const size_t template_size = (BLI_ghash_len(TEMPLATES_HASH) * 32 + 30); - - if (TEMPLATES_MENU != NULL) { - MEM_freeN(TEMPLATES_MENU); - } - - TEMPLATES_MENU = MEM_callocN(sizeof(char) * template_size, "skeleton template menu"); - - p = TEMPLATES_MENU; - p += BLI_strncpy_rlen(p, menu_header, template_size); - - BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); - - while (!BLI_ghashIterator_done(&ghi)) { - Object *ob = BLI_ghashIterator_getValue(&ghi); - int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi)); - - p += sprintf(p, "|%s %%x%i", ob->id.name + 2, key); - - BLI_ghashIterator_step(&ghi); - } - - return TEMPLATES_MENU; -} -#endif - -int BIF_currentTemplate(const bContext *C) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - - if (TEMPLATES_CURRENT == 0 && ts->skgen_template != NULL) { - GHashIterator ghi; - BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); - - while (!BLI_ghashIterator_done(&ghi)) { - Object *ob = BLI_ghashIterator_getValue(&ghi); - int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi)); - - if (ob == ts->skgen_template) { - TEMPLATES_CURRENT = key; - break; - } - - BLI_ghashIterator_step(&ghi); - } - } - - return TEMPLATES_CURRENT; -} - -static RigGraph *sk_makeTemplateGraph(const bContext *C, Object *ob) -{ - Object *obedit = CTX_data_edit_object(C); - if (ob == obedit) { - return NULL; - } - - if (ob != NULL) { - if (TEMPLATE_RIGG && TEMPLATE_RIGG->ob != ob) { - RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG); - TEMPLATE_RIGG = NULL; - } - - if (TEMPLATE_RIGG == NULL) { - bArmature *arm; - - arm = ob->data; - - TEMPLATE_RIGG = RIG_graphFromArmature(C, ob, arm); - } - } - - return TEMPLATE_RIGG; -} - -int BIF_nbJointsTemplate(const bContext *C) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - RigGraph *rg = sk_makeTemplateGraph(C, ts->skgen_template); - - if (rg) { - return RIG_nbJoints(rg); - } - else { - return -1; - } -} - -const char *BIF_nameBoneTemplate(const bContext *C) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - SK_Sketch *stk = contextSketch(C, 1); - RigGraph *rg; - int index = 0; - - if (stk && stk->active_stroke != NULL) { - index = stk->active_stroke->nb_points; - } - - rg = sk_makeTemplateGraph(C, ts->skgen_template); - - if (rg == NULL) { - return ""; - } - - return RIG_nameBone(rg, 0, index); -} - -void BIF_freeTemplates(bContext *UNUSED(C)) -{ - if (TEMPLATES_MENU != NULL) { - MEM_freeN(TEMPLATES_MENU); - TEMPLATES_MENU = NULL; - } - - if (TEMPLATES_HASH != NULL) { - BLI_ghash_free(TEMPLATES_HASH, NULL, NULL); - TEMPLATES_HASH = NULL; - } - - if (TEMPLATE_RIGG != NULL) { - RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG); - TEMPLATE_RIGG = NULL; - } -} - -void BIF_setTemplate(bContext *C, int index) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - if (index > 0) { - ts->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index)); - } - else { - ts->skgen_template = NULL; - - if (TEMPLATE_RIGG != NULL) { - RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG); - } - TEMPLATE_RIGG = NULL; - } -} - -/*********************** CONVERSION ***************************/ - -static void sk_autoname(bContext *C, ReebArc *arc) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - if (ts->skgen_retarget_options & SK_RETARGET_AUTONAME) { - if (arc == NULL) { - char *num = ts->skgen_num_string; - int i = atoi(num); - i++; - BLI_snprintf(num, 8, "%i", i); - } - else { - char *side = ts->skgen_side_string; - int valid = 0; - int caps = 0; - - if (side[0] == '\0') { - valid = 1; - } - else if (STREQ(side, "R") || STREQ(side, "L")) { - valid = 1; - caps = 1; - } - else if (STREQ(side, "r") || STREQ(side, "l")) { - valid = 1; - caps = 0; - } - - if (valid) { - if (arc->head->p[0] < 0) { - BLI_snprintf(side, 8, caps ? "R" : "r"); - } - else { - BLI_snprintf(side, 8, caps ? "L" : "l"); - } - } - } - } -} - -static ReebNode *sk_pointToNode(SK_Point *pt, float imat[4][4], float tmat[3][3]) -{ - ReebNode *node; - - node = MEM_callocN(sizeof(ReebNode), "reeb node"); - copy_v3_v3(node->p, pt->p); - mul_m4_v3(imat, node->p); - - copy_v3_v3(node->no, pt->no); - mul_m3_v3(tmat, node->no); - - return node; -} - -static ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[4][4], float tmat[3][3]) -{ - ReebArc *arc; - int i; - - arc = MEM_callocN(sizeof(ReebArc), "reeb arc"); - arc->head = sk_pointToNode(stk->points, imat, tmat); - arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat); - - arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */ - arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets"); - - for (i = 0; i < arc->bcount; i++) { - copy_v3_v3(arc->buckets[i].p, stk->points[i + 1].p); - mul_m4_v3(imat, arc->buckets[i].p); - - copy_v3_v3(arc->buckets[i].no, stk->points[i + 1].no); - mul_m3_v3(tmat, arc->buckets[i].no); - } - - return arc; -} - -static void sk_retargetStroke(bContext *C, SK_Stroke *stk) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - Object *obedit = CTX_data_edit_object(C); - float imat[4][4]; - float tmat[3][3]; - ReebArc *arc; - RigGraph *rg; - - invert_m4_m4(imat, obedit->obmat); - transpose_m3_m4(tmat, obedit->obmat); - - arc = sk_strokeToArc(stk, imat, tmat); - - sk_autoname(C, arc); - - rg = sk_makeTemplateGraph(C, ts->skgen_template); - - BIF_retargetArc(C, arc, rg); - - sk_autoname(C, NULL); - - MEM_freeN(arc->head); - MEM_freeN(arc->tail); - REEB_freeArc((BArc *)arc); -} - -/**************************************************************/ - -static void sk_cancelStroke(SK_Sketch *sketch) -{ - if (sketch->active_stroke != NULL) { - sk_resetOverdraw(sketch); - sk_removeStroke(sketch, sketch->active_stroke); - } -} - - -static float sk_clampPointSize(SK_Point *pt, float size) -{ - return max_ff(size * pt->size, size / 2); -} - -static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size) -{ - glTranslate3fv(pt->p); - gluSphere(quad, sk_clampPointSize(pt, size), 8, 8); -} - -static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float size) -{ - float vec1[3], vec2[3] = {0, 0, 1}, axis[3]; - float angle, length; - - sub_v3_v3v3(vec1, pt1->p, pt0->p); - length = normalize_v3(vec1); - cross_v3_v3v3(axis, vec2, vec1); - - if (is_zero_v3(axis)) { - axis[1] = 1; - } - - angle = angle_normalized_v3v3(vec2, vec1); - - glRotate3fv(angle * (float)(180.0 / M_PI) + 180.0f, axis); - - gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8); -} - -static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float height) -{ - float vec2[3] = {0, 0, 1}, axis[3]; - float angle; - - glPushMatrix(); - - cross_v3_v3v3(axis, vec2, pt->no); - - if (is_zero_v3(axis)) { - axis[1] = 1; - } - - angle = angle_normalized_v3v3(vec2, pt->no); - - glRotate3fv(angle * (float)(180.0 / M_PI), axis); - - glColor3f(0, 1, 1); - gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2); - - glPopMatrix(); -} - -static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end) -{ - float rgb[3]; - int i; - GLUquadric *quad = gluNewQuadric(); - gluQuadricNormals(quad, GLU_SMOOTH); - - if (id != -1) { - GPU_select_load_id(id); - - for (i = 0; i < stk->nb_points; i++) { - glPushMatrix(); - - sk_drawPoint(quad, stk->points + i, 0.1); - - if (i > 0) { - sk_drawEdge(quad, stk->points + i - 1, stk->points + i, 0.1); - } - - glPopMatrix(); - } - - } - else { - float d_rgb[3] = {1, 1, 1}; - - copy_v3_v3(rgb, color); - sub_v3_v3(d_rgb, rgb); - mul_v3_fl(d_rgb, 1.0f / (float)stk->nb_points); - - for (i = 0; i < stk->nb_points; i++) { - SK_Point *pt = stk->points + i; - - glPushMatrix(); - - if (pt->type == PT_EXACT) { - glColor3f(0, 0, 0); - sk_drawPoint(quad, pt, 0.15); - sk_drawNormal(quad, pt, 0.05, 0.9); - } - - if (i >= start && i <= end) { - glColor3f(0.3, 0.3, 0.3); - } - else { - glColor3fv(rgb); - } - - if (pt->type != PT_EXACT) { - - sk_drawPoint(quad, pt, 0.1); - } - - if (i > 0) { - sk_drawEdge(quad, pt - 1, pt, 0.1); - } - - glPopMatrix(); - - add_v3_v3(rgb, d_rgb); - } - } - - gluDeleteQuadric(quad); -} - -static void drawSubdividedStrokeBy(ToolSettings *toolsettings, BArcIterator *iter, NextSubdivisionFunc next_subdividion) -{ - SK_Stroke *stk = ((SK_StrokeIterator *)iter)->stroke; - float head[3], tail[3]; - int bone_start = 0; - int end = iter->length; - int index; - GLUquadric *quad = gluNewQuadric(); - gluQuadricNormals(quad, GLU_SMOOTH); - - iter->head(iter); - copy_v3_v3(head, iter->p); - - index = next_subdividion(toolsettings, iter, bone_start, end, head, tail); - while (index != -1) { - SK_Point *pt = stk->points + index; - - glPushMatrix(); - - glColor3f(0, 1, 0); - sk_drawPoint(quad, pt, 0.15); - - sk_drawNormal(quad, pt, 0.05, 0.9); - - glPopMatrix(); - - copy_v3_v3(head, tail); - bone_start = index; // start next bone from current index - - index = next_subdividion(toolsettings, iter, bone_start, end, head, tail); - } - - gluDeleteQuadric(quad); -} - -static void sk_drawStrokeSubdivision(ToolSettings *toolsettings, SK_Stroke *stk) -{ - int head_index = -1; - int i; - - if (toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET) { - return; - } - - - for (i = 0; i < stk->nb_points; i++) { - SK_Point *pt = stk->points + i; - - if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */ { - if (head_index == -1) { - head_index = i; - } - else { - if (i - head_index > 1) { - SK_StrokeIterator sk_iter; - BArcIterator *iter = (BArcIterator *)&sk_iter; - - initStrokeIterator(iter, stk, head_index, i); - - if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) { - drawSubdividedStrokeBy(toolsettings, iter, nextAdaptativeSubdivision); - } - else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) { - drawSubdividedStrokeBy(toolsettings, iter, nextLengthSubdivision); - } - else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED) { - drawSubdividedStrokeBy(toolsettings, iter, nextFixedSubdivision); - } - - } - - head_index = i; - } - } - } -} - -static SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, int mval[2], float *r_dist_px, int *index, int all_pts) -{ - ARegion *ar = CTX_wm_region(C); - SK_Point *pt = NULL; - int i; - - for (i = 0; i < stk->nb_points; i++) { - if (all_pts || stk->points[i].type == PT_EXACT) { - short pval[2]; - int pdist; - - if (ED_view3d_project_short_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - - pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); - - if (pdist < *r_dist_px) { - *r_dist_px = pdist; - pt = stk->points + i; - - if (index != NULL) { - *index = i; - } - } - } - } - } - - return pt; -} - -#if 0 /* UNUSED 2.5 */ -static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, int mval[2], int *dist) -{ - ARegion *ar = CTX_wm_region(C); - SK_Point *pt = NULL; - EditBone *bone; - - for (bone = ebones->first; bone; bone = bone->next) - { - float vec[3]; - short pval[2]; - int pdist; - - if ((bone->flag & BONE_CONNECTED) == 0) - { - copy_v3_v3(vec, bone->head); - mul_m4_v3(ob->obmat, vec); - if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - - pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); - - if (pdist < *dist) - { - *dist = pdist; - pt = &boneSnap; - copy_v3_v3(pt->p, vec); - pt->type = PT_EXACT; - } - } - } - - - copy_v3_v3(vec, bone->tail); - mul_m4_v3(ob->obmat, vec); - if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - - pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); - - if (pdist < *dist) - { - *dist = pdist; - pt = &boneSnap; - copy_v3_v3(pt->p, vec); - pt->type = PT_EXACT; - } - } - } - - return pt; -} -#endif - -void sk_resetOverdraw(SK_Sketch *sketch) -{ - sketch->over.target = NULL; - sketch->over.start = -1; - sketch->over.end = -1; - sketch->over.count = 0; -} - -int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk) -{ - return sketch->over.target && - sketch->over.count >= SK_OVERDRAW_LIMIT && - (sketch->over.target == stk || stk == NULL) && - (sketch->over.start != -1 || sketch->over.end != -1); -} - -static void sk_updateOverdraw(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) -{ - if (sketch->over.target == NULL) { - SK_Stroke *target; - int closest_index = -1; - float dist_px = SNAP_MIN_DISTANCE * 2; - - for (target = sketch->strokes.first; target; target = target->next) { - if (target != stk) { - int index; - - SK_Point *spt = sk_snapPointStroke(C, target, dd->mval, &dist_px, &index, 1); - - if (spt != NULL) { - sketch->over.target = target; - closest_index = index; - } - } - } - - if (sketch->over.target != NULL) { - if (closest_index > -1) { - if (sk_lastStrokePoint(stk)->type == PT_EXACT) { - sketch->over.count = SK_OVERDRAW_LIMIT; - } - else { - sketch->over.count++; - } - } - - if (stk->nb_points == 1) { - sketch->over.start = closest_index; - } - else { - sketch->over.end = closest_index; - } - } - } - else if (sketch->over.target != NULL) { - SK_Point *closest_pt = NULL; - float dist_px = SNAP_MIN_DISTANCE * 2; - int index; - - closest_pt = sk_snapPointStroke(C, sketch->over.target, dd->mval, &dist_px, &index, 1); - - if (closest_pt != NULL) { - if (sk_lastStrokePoint(stk)->type == PT_EXACT) { - sketch->over.count = SK_OVERDRAW_LIMIT; - } - else { - sketch->over.count++; - } - - sketch->over.end = index; - } - else { - sketch->over.end = -1; - } - } -} - -/* return 1 on reverse needed */ -static int sk_adjustIndexes(SK_Sketch *sketch, int *start, int *end) -{ - int retval = 0; - - *start = sketch->over.start; - *end = sketch->over.end; - - if (*start == -1) { - *start = 0; - } - - if (*end == -1) { - *end = sketch->over.target->nb_points - 1; - } - - if (*end < *start) { - int tmp = *start; - *start = *end; - *end = tmp; - retval = 1; - } - - return retval; -} - -static void sk_endOverdraw(SK_Sketch *sketch) -{ - SK_Stroke *stk = sketch->active_stroke; - - if (sk_hasOverdraw(sketch, NULL)) { - int start; - int end; - - if (sk_adjustIndexes(sketch, &start, &end)) { - sk_reverseStroke(stk); - } - - if (stk->nb_points > 1) { - stk->points->type = sketch->over.target->points[start].type; - sk_lastStrokePoint(stk)->type = sketch->over.target->points[end].type; - } - - sk_insertStrokePoints(sketch->over.target, stk->points, stk->nb_points, start, end); - - sk_removeStroke(sketch, stk); - - sk_resetOverdraw(sketch); - } -} - - -static void sk_startStroke(SK_Sketch *sketch) -{ - SK_Stroke *stk = sk_createStroke(); - - BLI_addtail(&sketch->strokes, stk); - sketch->active_stroke = stk; - - sk_resetOverdraw(sketch); -} - -static void sk_endStroke(bContext *C, SK_Sketch *sketch) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - sk_shrinkStrokeBuffer(sketch->active_stroke); - - if (ts->bone_sketching & BONE_SKETCHING_ADJUST) { - sk_endOverdraw(sketch); - } - - sketch->active_stroke = NULL; -} - -static void sk_updateDrawData(SK_DrawData *dd) -{ - dd->type = PT_CONTINUOUS; - - dd->previous_mval[0] = dd->mval[0]; - dd->previous_mval[1] = dd->mval[1]; -} - -static float sk_distanceDepth(bContext *C, float p1[3], float p2[3]) -{ - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - float vec[3]; - float distance; - - sub_v3_v3v3(vec, p1, p2); - - project_v3_v3v3(vec, vec, rv3d->viewinv[2]); - - distance = len_v3(vec); - - if (dot_v3v3(rv3d->viewinv[2], vec) > 0) { - distance *= -1; - } - - return distance; -} - -static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float length, float distance) -{ - ARegion *ar = CTX_wm_region(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - - float progress = 0; - int i; - - progress = len_v3v3(stk->points[start].p, stk->points[start - 1].p); - - for (i = start; i <= end; i++) { - float ray_start[3], ray_normal[3]; - float delta = len_v3v3(stk->points[i].p, stk->points[i + 1].p); - float pval[2] = {0, 0}; - - ED_view3d_project_float_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP); - ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal, false); - - mul_v3_fl(ray_normal, distance * progress / length); - add_v3_v3(stk->points[i].p, ray_normal); - - progress += delta; - } -} - -static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_DrawData *dd) -{ - ARegion *ar = CTX_wm_region(C); - /* copied from grease pencil, need fixing */ - SK_Point *last = sk_lastStrokePoint(stk); - short cval[2]; - float fp[3] = {0, 0, 0}; - float dvec[3]; - float mval_f[2]; - float zfac; - - if (last != NULL) { - copy_v3_v3(fp, last->p); - } - - zfac = ED_view3d_calc_zfac(ar->regiondata, fp, NULL); - - if (ED_view3d_project_short_global(ar, fp, cval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - VECSUB2D(mval_f, cval, dd->mval); - ED_view3d_win_to_delta(ar, mval_f, dvec, zfac); - sub_v3_v3v3(vec, fp, dvec); - } - else { - zero_v3(vec); - } -} - -static int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *UNUSED(sketch), SK_Stroke *stk, SK_DrawData *dd) -{ - pt->type = dd->type; - pt->mode = PT_PROJECT; - sk_projectDrawPoint(C, pt->p, stk, dd); - - return 1; -} - -static int sk_addStrokeDrawPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) -{ - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - SK_Point pt; - - sk_initPoint(&pt, dd, rv3d->viewinv[2]); - - sk_getStrokeDrawPoint(C, &pt, sketch, stk, dd); - - sk_appendStrokePoint(stk, &pt); - - return 1; -} - -static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - int point_added = 0; - - /* TODO: Since the function `ED_transform_snap_object_context_create_view3d` creates a cache, - * the ideal would be to call this function only at the beginning of the snap operation, - * or at the beginning of the operator itself */ - struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), 0, - CTX_wm_region(C), CTX_wm_view3d(C)); - - float mvalf[2] = {UNPACK2(dd->mval)}; - float loc[3], dummy_no[3]; - - if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) { - float size; - if (peelObjectsSnapContext( - snap_context, mvalf, - &(const struct SnapObjectParams){ - .snap_select = SNAP_NOT_SELECTED, - .use_object_edit_cage = false, - }, - (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, - loc, dummy_no, &size)) - { - pt->type = dd->type; - pt->mode = PT_SNAP; - pt->size = size / 2; - copy_v3_v3(pt->p, loc); - - point_added = 1; - } - } - else { - SK_Stroke *snap_stk; - float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here - - /* snap to strokes */ - // if (ts->snap_mode == SCE_SNAP_MODE_VERTEX) /* snap all the time to strokes */ - for (snap_stk = sketch->strokes.first; snap_stk; snap_stk = snap_stk->next) { - SK_Point *spt = NULL; - if (snap_stk == stk) { - spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist_px, NULL, 0); - } - else { - spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist_px, NULL, 1); - } - - if (spt != NULL) { - copy_v3_v3(pt->p, spt->p); - point_added = 1; - } - } - - /* try to snap to closer object */ - { - if (ED_transform_snap_object_project_view3d( - snap_context, - ts->snap_mode, - &(const struct SnapObjectParams){ - .snap_select = SNAP_NOT_SELECTED, - .use_object_edit_cage = false, - }, - mvalf, &dist_px, NULL, - loc, dummy_no)) - { - pt->type = dd->type; - pt->mode = PT_SNAP; - copy_v3_v3(pt->p, loc); - - point_added = 1; - } - } - } - - /* TODO: The ideal would be to call this function only once. - * At the end of the operator */ - ED_transform_snap_object_context_destroy(snap_context); - return point_added; -} - -static int sk_addStrokeSnapPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) -{ - int point_added; - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - SK_Point pt; - - sk_initPoint(&pt, dd, rv3d->viewinv[2]); - - point_added = sk_getStrokeSnapPoint(C, &pt, sketch, stk, dd); - - if (point_added) { - float final_p[3]; - float length, distance; - int total; - int i; - - copy_v3_v3(final_p, pt.p); - - sk_projectDrawPoint(C, pt.p, stk, dd); - sk_appendStrokePoint(stk, &pt); - - /* update all previous point to give smooth Z progresion */ - total = 0; - length = 0; - for (i = stk->nb_points - 2; i > 0; i--) { - length += len_v3v3(stk->points[i].p, stk->points[i + 1].p); - total++; - if (stk->points[i].mode == PT_SNAP || stk->points[i].type == PT_EXACT) { - break; - } - } - - if (total > 1) { - distance = sk_distanceDepth(C, final_p, stk->points[i].p); - - sk_interpolateDepth(C, stk, i + 1, stk->nb_points - 2, length, distance); - } - - copy_v3_v3(stk->points[stk->nb_points - 1].p, final_p); - - point_added = 1; - } - - return point_added; -} - -static void sk_addStrokePoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, const bool snap) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - int point_added = 0; - - if (snap) { - point_added = sk_addStrokeSnapPoint(C, sketch, stk, dd); - } - - if (point_added == 0) { - point_added = sk_addStrokeDrawPoint(C, sketch, stk, dd); - } - - if (stk == sketch->active_stroke && ts->bone_sketching & BONE_SKETCHING_ADJUST) { - sk_updateOverdraw(C, sketch, stk, dd); - } -} - -static void sk_getStrokePoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, const bool snap) -{ - int point_added = 0; - - if (snap) { - point_added = sk_getStrokeSnapPoint(C, pt, sketch, stk, dd); - LAST_SNAP_POINT_VALID = 1; - copy_v3_v3(LAST_SNAP_POINT, pt->p); - } - else { - LAST_SNAP_POINT_VALID = 0; - } - - if (point_added == 0) { - point_added = sk_getStrokeDrawPoint(C, pt, sketch, stk, dd); - } -} - -/********************************************/ - -static void *headPoint(void *arg); -static void *tailPoint(void *arg); -static void *nextPoint(void *arg); -static void *nextNPoint(void *arg, int n); -static void *peekPoint(void *arg, int n); -static void *previousPoint(void *arg); -static int iteratorStopped(void *arg); - -static void initIteratorFct(SK_StrokeIterator *iter) -{ - iter->head = headPoint; - iter->tail = tailPoint; - iter->peek = peekPoint; - iter->next = nextPoint; - iter->nextN = nextNPoint; - iter->previous = previousPoint; - iter->stopped = iteratorStopped; -} - -static SK_Point *setIteratorValues(SK_StrokeIterator *iter, int index) -{ - SK_Point *pt = NULL; - - if (index >= 0 && index < iter->length) { - pt = &(iter->stroke->points[iter->start + (iter->stride * index)]); - iter->p = pt->p; - iter->no = pt->no; - iter->size = pt->size; - } - else { - iter->p = NULL; - iter->no = NULL; - iter->size = 0; - } - - return pt; -} - -void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - - initIteratorFct(iter); - iter->stroke = stk; - - if (start < end) { - iter->start = start + 1; - iter->end = end - 1; - iter->stride = 1; - } - else { - iter->start = start - 1; - iter->end = end + 1; - iter->stride = -1; - } - - iter->length = iter->stride * (iter->end - iter->start + 1); - - iter->index = -1; -} - - -static void *headPoint(void *arg) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - SK_Point *result = NULL; - - result = &(iter->stroke->points[iter->start - iter->stride]); - iter->p = result->p; - iter->no = result->no; - iter->size = result->size; - - return result; -} - -static void *tailPoint(void *arg) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - SK_Point *result = NULL; - - result = &(iter->stroke->points[iter->end + iter->stride]); - iter->p = result->p; - iter->no = result->no; - iter->size = result->size; - - return result; -} - -static void *nextPoint(void *arg) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - SK_Point *result = NULL; - - iter->index++; - if (iter->index < iter->length) { - result = setIteratorValues(iter, iter->index); - } - - return result; -} - -static void *nextNPoint(void *arg, int n) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - SK_Point *result = NULL; - - iter->index += n; - - /* check if passed end */ - if (iter->index < iter->length) { - result = setIteratorValues(iter, iter->index); - } - - return result; -} - -static void *peekPoint(void *arg, int n) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - SK_Point *result = NULL; - int index = iter->index + n; - - /* check if passed end */ - if (index < iter->length) { - result = setIteratorValues(iter, index); - } - - return result; -} - -static void *previousPoint(void *arg) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - SK_Point *result = NULL; - - if (iter->index > 0) { - iter->index--; - result = setIteratorValues(iter, iter->index); - } - - return result; -} - -static int iteratorStopped(void *arg) -{ - SK_StrokeIterator *iter = (SK_StrokeIterator *)arg; - - if (iter->index >= iter->length) { - return 1; - } - else { - return 0; - } -} - -static void sk_convertStroke(bContext *C, SK_Stroke *stk) -{ - Object *obedit = CTX_data_edit_object(C); - ToolSettings *ts = CTX_data_tool_settings(C); - bArmature *arm = obedit->data; - SK_Point *head; - EditBone *parent = NULL; - float invmat[4][4]; /* move in caller function */ - float tmat[3][3]; - int head_index = 0; - int i; - - head = NULL; - - invert_m4_m4(invmat, obedit->obmat); - transpose_m3_m4(tmat, obedit->obmat); - - for (i = 0; i < stk->nb_points; i++) { - SK_Point *pt = stk->points + i; - - if (pt->type == PT_EXACT) { - if (head == NULL) { - head_index = i; - head = pt; - } - else { - EditBone *bone = NULL; - EditBone *new_parent; - - if (i - head_index > 1) { - SK_StrokeIterator sk_iter; - BArcIterator *iter = (BArcIterator *)&sk_iter; - - initStrokeIterator(iter, stk, head_index, i); - - if (ts->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) { - bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision); - } - else if (ts->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) { - bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision); - } - else if (ts->bone_sketching_convert == SK_CONVERT_CUT_FIXED) { - bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextFixedSubdivision); - } - } - - if (bone == NULL) { - bone = ED_armature_ebone_add(arm, "Bone"); - - copy_v3_v3(bone->head, head->p); - copy_v3_v3(bone->tail, pt->p); - - mul_m4_v3(invmat, bone->head); - mul_m4_v3(invmat, bone->tail); - setBoneRollFromNormal(bone, head->no, invmat, tmat); - } - - new_parent = bone; - bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; - - /* move to end of chain */ - while (bone->parent != NULL) { - bone = bone->parent; - bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; - } - - if (parent != NULL) { - bone->parent = parent; - bone->flag |= BONE_CONNECTED; - } - - parent = new_parent; - head_index = i; - head = pt; - } - } - } -} - -static void sk_convert(bContext *C, SK_Sketch *sketch) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - SK_Stroke *stk; - - for (stk = sketch->strokes.first; stk; stk = stk->next) { - if (stk->selected == 1) { - if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) { - sk_retargetStroke(C, stk); - } - else { - sk_convertStroke(C, stk); - } -// XXX -// allqueue(REDRAWBUTSEDIT, 0); - } - } -} -/******************* GESTURE *************************/ - - -/* returns the number of self intersections */ -static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gesture) -{ - ARegion *ar = CTX_wm_region(C); - int added = 0; - int s_i; - - for (s_i = 0; s_i < gesture->nb_points - 1; s_i++) { - float s_p1[3] = {0, 0, 0}; - float s_p2[3] = {0, 0, 0}; - int g_i; - - ED_view3d_project_float_global(ar, gesture->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP); - ED_view3d_project_float_global(ar, gesture->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP); - - /* start checking from second next, because two consecutive cannot intersect */ - for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++) { - float g_p1[3] = {0, 0, 0}; - float g_p2[3] = {0, 0, 0}; - float vi[3]; - float lambda; - - ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP); - ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP); - - if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) { - SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); - - isect->gesture_index = g_i; - isect->before = s_i; - isect->after = s_i + 1; - isect->stroke = gesture; - - sub_v3_v3v3(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p); - mul_v3_fl(isect->p, lambda); - add_v3_v3(isect->p, gesture->points[s_i].p); - - BLI_addtail(list, isect); - - added++; - } - } - } - - return added; -} - -static int cmpIntersections(const void *i1, const void *i2) -{ - const SK_Intersection *isect1 = i1, *isect2 = i2; - - if (isect1->stroke == isect2->stroke) { - if (isect1->before < isect2->before) { - return -1; - } - else if (isect1->before > isect2->before) { - return 1; - } - else { - if (isect1->lambda < isect2->lambda) { - return -1; - } - else if (isect1->lambda > isect2->lambda) { - return 1; - } - } - } - - return 0; -} - - -/* returns the maximum number of intersections per stroke */ -static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture) -{ - ARegion *ar = CTX_wm_region(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - SK_Stroke *stk; - int added = 0; - - for (stk = sketch->strokes.first; stk; stk = stk->next) { - int s_added = 0; - int s_i; - - for (s_i = 0; s_i < stk->nb_points - 1; s_i++) { - float s_p1[3] = {0, 0, 0}; - float s_p2[3] = {0, 0, 0}; - int g_i; - - ED_view3d_project_float_global(ar, stk->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP); - ED_view3d_project_float_global(ar, stk->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP); - - for (g_i = 0; g_i < gesture->nb_points - 1; g_i++) { - float g_p1[3] = {0, 0, 0}; - float g_p2[3] = {0, 0, 0}; - float vi[3]; - float lambda; - - ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP); - ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP); - - if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) { - SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); - float ray_start[3], ray_end[3]; - float mval[2]; - - isect->gesture_index = g_i; - isect->before = s_i; - isect->after = s_i + 1; - isect->stroke = stk; - isect->lambda = lambda; - - mval[0] = vi[0]; - mval[1] = vi[1]; - ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end, true); - - isect_line_line_v3(stk->points[s_i].p, - stk->points[s_i + 1].p, - ray_start, - ray_end, - isect->p, - vi); - - BLI_addtail(list, isect); - - s_added++; - } - } - } - - added = MAX2(s_added, added); - } - - BLI_listbase_sort(list, cmpIntersections); - - return added; -} - -static int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture) -{ - SK_StrokeIterator sk_iter; - BArcIterator *iter = (BArcIterator *)&sk_iter; - - float CORRELATION_THRESHOLD = 0.99f; - float *vec; - int i, j; - - sk_appendStrokePoint(segments, &gesture->points[0]); - vec = segments->points[segments->nb_points - 1].p; - - initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1); - - for (i = 1, j = 0; i < gesture->nb_points; i++) { - float n[3]; - - /* Calculate normal */ - sub_v3_v3v3(n, gesture->points[i].p, vec); - - if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD) { - j = i - 1; - sk_appendStrokePoint(segments, &gesture->points[j]); - vec = segments->points[segments->nb_points - 1].p; - segments->points[segments->nb_points - 1].type = PT_EXACT; - } - } - - sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]); - - return segments->nb_points - 1; -} - -int sk_detectCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - if (gest->nb_segments == 1 && gest->nb_intersections == 1) { - return 1; - } - - return 0; -} - -void sk_applyCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - SK_Intersection *isect; - - for (isect = gest->intersections.first; isect; isect = isect->next) { - SK_Point pt; - - pt.type = PT_EXACT; - pt.mode = PT_PROJECT; /* take mode from neighboring points */ - copy_v3_v3(pt.p, isect->p); - copy_v3_v3(pt.no, isect->stroke->points[isect->before].no); - - sk_insertStrokePoint(isect->stroke, &pt, isect->after); - } -} - -int sk_detectTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - if (gest->nb_segments == 2 && gest->nb_intersections == 1 && gest->nb_self_intersections == 0) { - float s1[3], s2[3]; - float angle; - - sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p); - sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p); - - angle = RAD2DEGF(angle_v2v2(s1, s2)); - - if (angle > 60 && angle < 120) { - return 1; - } - } - - return 0; -} - -void sk_applyTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - SK_Intersection *isect; - float trim_dir[3]; - - sub_v3_v3v3(trim_dir, gest->segments->points[2].p, gest->segments->points[1].p); - - for (isect = gest->intersections.first; isect; isect = isect->next) { - SK_Point pt; - float stroke_dir[3]; - - pt.type = PT_EXACT; - pt.mode = PT_PROJECT; /* take mode from neighboring points */ - copy_v3_v3(pt.p, isect->p); - copy_v3_v3(pt.no, isect->stroke->points[isect->before].no); - - sub_v3_v3v3(stroke_dir, isect->stroke->points[isect->after].p, isect->stroke->points[isect->before].p); - - /* same direction, trim end */ - if (dot_v3v3(stroke_dir, trim_dir) > 0) { - sk_replaceStrokePoint(isect->stroke, &pt, isect->after); - sk_trimStroke(isect->stroke, 0, isect->after); - } - /* else, trim start */ - else { - sk_replaceStrokePoint(isect->stroke, &pt, isect->before); - sk_trimStroke(isect->stroke, isect->before, isect->stroke->nb_points - 1); - } - - } -} - -int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1) { - SK_Intersection *isect, *self_isect; - - /* get the last intersection of the first pair */ - for (isect = gest->intersections.first; isect; isect = isect->next) { - if (isect->stroke == isect->next->stroke) { - isect = isect->next; - break; - } - } - - self_isect = gest->self_intersections.first; - - if (isect && isect->gesture_index < self_isect->gesture_index) { - return 1; - } - } - - return 0; -} - -void sk_applyCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - SK_Intersection *isect; - int command = 1; - -/* XXX */ -/* command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3"); */ - if (command < 1) return; - - for (isect = gest->intersections.first; isect; isect = isect->next) { - SK_Intersection *i2; - - i2 = isect->next; - - if (i2 && i2->stroke == isect->stroke) { - switch (command) { - case 1: - sk_flattenStroke(isect->stroke, isect->before, i2->after); - break; - case 2: - sk_straightenStroke(isect->stroke, isect->before, i2->after, isect->p, i2->p); - break; - case 3: - sk_polygonizeStroke(isect->stroke, isect->before, i2->after); - break; - } - - isect = i2; - } - } -} - -int sk_detectDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - if (gest->nb_segments == 2 && gest->nb_intersections == 2) { - float s1[3], s2[3]; - float angle; - - sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p); - sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p); - - angle = RAD2DEGF(angle_v2v2(s1, s2)); - - if (angle > 120) { - return 1; - } - } - - return 0; -} - -void sk_applyDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *sketch) -{ - SK_Intersection *isect; - - for (isect = gest->intersections.first; isect; isect = isect->next) { - /* only delete strokes that are crossed twice */ - if (isect->next && isect->next->stroke == isect->stroke) { - isect = isect->next; - - sk_removeStroke(sketch, isect->stroke); - } - } -} - -int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - ARegion *ar = CTX_wm_region(C); - if (gest->nb_segments > 2 && gest->nb_intersections == 2) { - int start_val[2], end_val[2]; - int dist; - - if ((ED_view3d_project_int_global(ar, gest->stk->points[0].p, start_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && - (ED_view3d_project_int_global(ar, sk_lastStrokePoint(gest->stk)->p, end_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) - { - dist = len_manhattan_v2v2_int(start_val, end_val); - - /* if gesture is a circle */ - if (dist <= 20) { - SK_Intersection *isect; - - /* check if it circled around an exact point */ - for (isect = gest->intersections.first; isect; isect = isect->next) { - /* only delete strokes that are crossed twice */ - if (isect->next && isect->next->stroke == isect->stroke) { - int start_index, end_index; - int i; - - start_index = MIN2(isect->after, isect->next->after); - end_index = MAX2(isect->before, isect->next->before); - - for (i = start_index; i <= end_index; i++) { - if (isect->stroke->points[i].type == PT_EXACT) { - return 1; /* at least one exact point found, stop detect here */ - } - } - - /* skip next */ - isect = isect->next; - } - } - } - } - } - - return 0; -} - -void sk_applyMergeGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - SK_Intersection *isect; - - /* check if it circled around an exact point */ - for (isect = gest->intersections.first; isect; isect = isect->next) { - /* only merge strokes that are crossed twice */ - if (isect->next && isect->next->stroke == isect->stroke) { - int start_index, end_index; - int i; - - start_index = MIN2(isect->after, isect->next->after); - end_index = MAX2(isect->before, isect->next->before); - - for (i = start_index; i <= end_index; i++) { - /* if exact, switch to continuous */ - if (isect->stroke->points[i].type == PT_EXACT) { - isect->stroke->points[i].type = PT_CONTINUOUS; - } - } - - /* skip next */ - isect = isect->next; - } - } -} - -int sk_detectReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 0) { - SK_Intersection *isect; - - /* check if it circled around an exact point */ - for (isect = gest->intersections.first; isect; isect = isect->next) { - /* only delete strokes that are crossed twice */ - if (isect->next && isect->next->stroke == isect->stroke) { - float start_v[3], end_v[3]; - float angle; - - if (isect->gesture_index < isect->next->gesture_index) { - sub_v3_v3v3(start_v, isect->p, gest->stk->points[0].p); - sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->next->p); - } - else { - sub_v3_v3v3(start_v, isect->next->p, gest->stk->points[0].p); - sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p); - } - - angle = RAD2DEGF(angle_v2v2(start_v, end_v)); - - if (angle > 120) { - return 1; - } - - /* skip next */ - isect = isect->next; - } - } - } - - return 0; -} - -void sk_applyReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - SK_Intersection *isect; - - for (isect = gest->intersections.first; isect; isect = isect->next) { - /* only reverse strokes that are crossed twice */ - if (isect->next && isect->next->stroke == isect->stroke) { - sk_reverseStroke(isect->stroke); - - /* skip next */ - isect = isect->next; - } - } -} - -int sk_detectConvertGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) -{ - if (gest->nb_segments == 3 && gest->nb_self_intersections == 1) { - return 1; - } - return 0; -} - -void sk_applyConvertGesture(bContext *C, SK_Gesture *UNUSED(gest), SK_Sketch *sketch) -{ - sk_convert(C, sketch); -} - -static void sk_initGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) -{ - BLI_listbase_clear(&gest->intersections); - BLI_listbase_clear(&gest->self_intersections); - - gest->segments = sk_createStroke(); - gest->stk = sketch->gesture; - - gest->nb_self_intersections = sk_getSelfIntersections(C, &gest->self_intersections, gest->stk); - gest->nb_intersections = sk_getIntersections(C, &gest->intersections, sketch, gest->stk); - gest->nb_segments = sk_getSegments(gest->segments, gest->stk); -} - -static void sk_freeGesture(SK_Gesture *gest) -{ - sk_freeStroke(gest->segments); - BLI_freelistN(&gest->intersections); - BLI_freelistN(&gest->self_intersections); -} - -static void sk_applyGesture(bContext *C, SK_Sketch *sketch) -{ - SK_Gesture gest; - SK_GestureAction *act; - - sk_initGesture(C, &gest, sketch); - - /* detect and apply */ - for (act = GESTURE_ACTIONS; act->apply != NULL; act++) { - if (act->detect(C, &gest, sketch)) { - act->apply(C, &gest, sketch); - break; - } - } - - sk_freeGesture(&gest); -} - -/********************************************/ - - -static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], const bool extend) -{ - ViewContext vc; - rcti rect; - unsigned int buffer[MAXPICKBUF]; - short hits; - - ED_view3d_viewcontext_init(C, &vc); - - BLI_rcti_init_pt_radius(&rect, mval, 5); - - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST); - - if (hits > 0) { - int besthitresult = -1; - - if (hits == 1) { - besthitresult = buffer[3]; - } - else { - besthitresult = buffer[3]; - /* loop and get best hit */ - } - - if (besthitresult > 0) { - SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1); - - if (extend == 0) { - sk_selectAllSketch(sketch, -1); - - selected_stk->selected = 1; - } - else { - selected_stk->selected ^= 1; - } - - - } - return 1; - } - - return 0; -} - -#if 0 /* UNUSED 2.5 */ -static void sk_queueRedrawSketch(SK_Sketch *sketch) -{ - if (sketch->active_stroke != NULL) - { - SK_Point *last = sk_lastStrokePoint(sketch->active_stroke); - - if (last != NULL) - { -// XXX -// allqueue(REDRAWVIEW3D, 0); - } - } -} -#endif - -static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, int with_names) -{ - ToolSettings *ts = scene->toolsettings; - SK_Stroke *stk; - - glClear(GL_DEPTH_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); - - if (with_names) { - int id; - for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next) { - sk_drawStroke(stk, id, NULL, -1, -1); - } - - GPU_select_load_id(-1); - } - else { - float selected_rgb[3] = {1, 0, 0}; - float unselected_rgb[3] = {1, 0.5, 0}; - - for (stk = sketch->strokes.first; stk; stk = stk->next) { - int start = -1; - int end = -1; - - if (sk_hasOverdraw(sketch, stk)) { - sk_adjustIndexes(sketch, &start, &end); - } - - sk_drawStroke(stk, -1, (stk->selected == 1 ? selected_rgb : unselected_rgb), start, end); - - if (stk->selected == 1) { - sk_drawStrokeSubdivision(ts, stk); - } - } - - if (sketch->active_stroke != NULL) { - SK_Point *last = sk_lastStrokePoint(sketch->active_stroke); - - if (ts->bone_sketching & BONE_SKETCHING_QUICK) { - sk_drawStrokeSubdivision(ts, sketch->active_stroke); - } - - if (last != NULL) { - GLUquadric *quad = gluNewQuadric(); - gluQuadricNormals(quad, GLU_SMOOTH); - - glPushMatrix(); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - switch (sketch->next_point.mode) { - case PT_SNAP: - glColor3f(0, 1, 0); - break; - case PT_PROJECT: - glColor3f(0, 0, 0); - break; - } - - sk_drawPoint(quad, &sketch->next_point, 0.1); - - glColor4f(selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3); - - sk_drawEdge(quad, last, &sketch->next_point, 0.1); - - glDisable(GL_BLEND); - - glPopMatrix(); - - gluDeleteQuadric(quad); - } - } - } - -#if 0 - if (BLI_listbase_is_empty(&sketch->depth_peels) == false) { - float colors[8][3] = { - {1, 0, 0}, - {0, 1, 0}, - {0, 0, 1}, - {1, 1, 0}, - {1, 0, 1}, - {0, 1, 1}, - {1, 1, 1}, - {0, 0, 0} - }; - DepthPeel *p; - GLUquadric *quad = gluNewQuadric(); - gluQuadricNormals(quad, GLU_SMOOTH); - - for (p = sketch->depth_peels.first; p; p = p->next) - { - int index = GET_INT_FROM_POINTER(p->ob); - index = (index >> 5) & 7; - - glColor3fv(colors[index]); - glPushMatrix(); - glTranslate3fv(p->p); - gluSphere(quad, 0.02, 8, 8); - glPopMatrix(); - } - - gluDeleteQuadric(quad); - } -#endif - - glDisable(GL_DEPTH_TEST); - - /* only draw gesture in active area */ - if (sketch->gesture != NULL /* && area_is_active_area(G.vd->area) */) { - float gesture_rgb[3] = {0, 0.5, 1}; - sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1); - } -} - -static int sk_finish_stroke(bContext *C, SK_Sketch *sketch) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - - if (sketch->active_stroke != NULL) { - SK_Stroke *stk = sketch->active_stroke; - - sk_endStroke(C, sketch); - - if (ts->bone_sketching & BONE_SKETCHING_QUICK) { - if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) { - sk_retargetStroke(C, stk); - } - else { - sk_convertStroke(C, stk); - } -// XXX -// BIF_undo_push("Convert Sketch"); - sk_removeStroke(sketch, stk); -// XXX -// allqueue(REDRAWBUTSEDIT, 0); - } - -// XXX -// allqueue(REDRAWVIEW3D, 0); - return 1; - } - - return 0; -} - -static void sk_start_draw_stroke(SK_Sketch *sketch) -{ - if (sketch->active_stroke == NULL) { - sk_startStroke(sketch); - sk_selectAllSketch(sketch, -1); - - sketch->active_stroke->selected = 1; - } -} - -static void sk_start_draw_gesture(SK_Sketch *sketch) -{ - sketch->gesture = sk_createStroke(); -} - -static int sk_draw_stroke(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, bool snap) -{ - if (sk_stroke_filtermval(dd)) { - sk_addStrokePoint(C, sketch, stk, dd, snap); - sk_updateDrawData(dd); - sk_updateNextPoint(sketch, stk); - - return 1; - } - - return 0; -} - -static int ValidSketchViewContext(ViewContext *vc) -{ - Object *obedit = vc->obedit; - Scene *scene = vc->scene; - - if (obedit && - obedit->type == OB_ARMATURE && - scene->toolsettings->bone_sketching & BONE_SKETCHING) - { - return 1; - } - else { - return 0; - } -} - -int BDR_drawSketchNames(ViewContext *vc) -{ - if (ValidSketchViewContext(vc)) { - SK_Sketch *sketch = viewcontextSketch(vc, 0); - if (sketch) { - sk_drawSketch(vc->scene, vc->v3d, sketch, 1); - return 1; - } - } - - return 0; -} - -void BDR_drawSketch(const bContext *C) -{ - if (ED_operator_sketch_mode(C)) { - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch) { - sk_drawSketch(CTX_data_scene(C), CTX_wm_view3d(C), sketch, 0); - } - } -} - -static int sketch_delete(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) -{ - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch) { - sk_deleteSelectedStrokes(sketch); -// allqueue(REDRAWVIEW3D, 0); - } - WM_event_add_notifier(C, NC_SCREEN | ND_SKETCH | NA_REMOVED, NULL); - return OPERATOR_FINISHED; -} - -bool BIF_sk_selectStroke(bContext *C, const int mval[2], const bool extend) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - SK_Sketch *sketch = contextSketch(C, 0); - - if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING) { - if (sk_selectStroke(C, sketch, mval, extend)) { - ED_area_tag_redraw(CTX_wm_area(C)); - return true; - } - } - - return false; -} - -void BIF_convertSketch(bContext *C) -{ - if (ED_operator_sketch_full_mode(C)) { - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch) { - sk_convert(C, sketch); -// BIF_undo_push("Convert Sketch"); -// allqueue(REDRAWVIEW3D, 0); -// allqueue(REDRAWBUTSEDIT, 0); - } - } -} - -void BIF_deleteSketch(bContext *C) -{ - if (ED_operator_sketch_full_mode(C)) { - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch) { - sk_deleteSelectedStrokes(sketch); -// BIF_undo_push("Convert Sketch"); -// allqueue(REDRAWVIEW3D, 0); - } - } -} - -#if 0 -void BIF_selectAllSketch(bContext *C, int mode) -{ - if (BIF_validSketchMode(C)) - { - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch) - { - sk_selectAllSketch(sketch, mode); -// XXX -// allqueue(REDRAWVIEW3D, 0); - } - } -} -#endif - -SK_Sketch *contextSketch(const bContext *C, int create) -{ - Object *obedit = CTX_data_edit_object(C); - SK_Sketch *sketch = NULL; - - if (obedit && obedit->type == OB_ARMATURE) { - bArmature *arm = obedit->data; - - if (arm->sketch == NULL && create) { - arm->sketch = createSketch(); - } - sketch = arm->sketch; - } - - return sketch; -} - -SK_Sketch *viewcontextSketch(ViewContext *vc, int create) -{ - Object *obedit = vc->obedit; - SK_Sketch *sketch = NULL; - - if (obedit && obedit->type == OB_ARMATURE) { - bArmature *arm = obedit->data; - - if (arm->sketch == NULL && create) { - arm->sketch = createSketch(); - } - sketch = arm->sketch; - } - - return sketch; -} - -static int sketch_convert(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) -{ - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch != NULL) { - sk_convert(C, sketch); - ED_area_tag_redraw(CTX_wm_area(C)); - } - return OPERATOR_FINISHED; -} - -static int sketch_cancel_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) -{ - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch != NULL) { - sk_cancelStroke(sketch); - ED_area_tag_redraw(CTX_wm_area(C)); - return OPERATOR_FINISHED; - } - return OPERATOR_PASS_THROUGH; -} - -static int sketch_finish(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) -{ - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch != NULL) { - if (sk_finish_stroke(C, sketch)) { - ED_area_tag_redraw(CTX_wm_area(C)); - return OPERATOR_FINISHED; - } - } - return OPERATOR_PASS_THROUGH; -} - -static int sketch_select(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) -{ - SK_Sketch *sketch = contextSketch(C, 0); - if (sketch) { - short extend = 0; - if (sk_selectStroke(C, sketch, event->mval, extend)) - ED_area_tag_redraw(CTX_wm_area(C)); - } - - return OPERATOR_FINISHED; -} - -static void sketch_draw_stroke_cancel(bContext *C, wmOperator *op) -{ - SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ - sk_cancelStroke(sketch); - MEM_freeN(op->customdata); -} - -static int sketch_draw_stroke(bContext *C, wmOperator *op, const wmEvent *event) -{ - const bool snap = RNA_boolean_get(op->ptr, "snap"); - SK_DrawData *dd; - SK_Sketch *sketch = contextSketch(C, 1); - - op->customdata = dd = MEM_callocN(sizeof(SK_DrawData), "SketchDrawData"); - sk_initDrawData(dd, event->mval); - - sk_start_draw_stroke(sketch); - - sk_draw_stroke(C, sketch, sketch->active_stroke, dd, snap); - - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; -} - -static void sketch_draw_gesture_cancel(bContext *C, wmOperator *op) -{ - SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ - sk_cancelStroke(sketch); - MEM_freeN(op->customdata); -} - -static int sketch_draw_gesture(bContext *C, wmOperator *op, const wmEvent *event) -{ - const bool snap = RNA_boolean_get(op->ptr, "snap"); - SK_DrawData *dd; - SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ - sk_cancelStroke(sketch); - - op->customdata = dd = MEM_callocN(sizeof(SK_DrawData), "SketchDrawData"); - sk_initDrawData(dd, event->mval); - - sk_start_draw_gesture(sketch); - sk_draw_stroke(C, sketch, sketch->gesture, dd, snap); - - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; -} - -static int sketch_draw_modal(bContext *C, wmOperator *op, const wmEvent *event, short gesture, SK_Stroke *stk) -{ - bool snap = RNA_boolean_get(op->ptr, "snap"); - SK_DrawData *dd = op->customdata; - SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ - int retval = OPERATOR_RUNNING_MODAL; - - switch (event->type) { - case LEFTCTRLKEY: - case RIGHTCTRLKEY: - snap = event->ctrl != 0; - RNA_boolean_set(op->ptr, "snap", snap); - break; - case MOUSEMOVE: - case INBETWEEN_MOUSEMOVE: - dd->mval[0] = event->mval[0]; - dd->mval[1] = event->mval[1]; - sk_draw_stroke(C, sketch, stk, dd, snap); - ED_area_tag_redraw(CTX_wm_area(C)); - break; - case ESCKEY: - op->type->cancel(C, op); - ED_area_tag_redraw(CTX_wm_area(C)); - retval = OPERATOR_CANCELLED; - break; - case LEFTMOUSE: - if (event->val == KM_RELEASE) { - if (gesture == 0) { - sk_endContinuousStroke(stk); - sk_filterLastContinuousStroke(stk); - sk_updateNextPoint(sketch, stk); - ED_area_tag_redraw(CTX_wm_area(C)); - MEM_freeN(op->customdata); - retval = OPERATOR_FINISHED; - } - else { - sk_endContinuousStroke(stk); - sk_filterLastContinuousStroke(stk); - - if (stk->nb_points > 1) { - /* apply gesture here */ - sk_applyGesture(C, sketch); - } - - sk_freeStroke(stk); - sketch->gesture = NULL; - - ED_area_tag_redraw(CTX_wm_area(C)); - MEM_freeN(op->customdata); - retval = OPERATOR_FINISHED; - } - } - break; - } - - return retval; -} - -static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ - return sketch_draw_modal(C, op, event, 0, sketch->active_stroke); -} - -static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ - return sketch_draw_modal(C, op, event, 1, sketch->gesture); -} - -static int sketch_draw_preview(bContext *C, wmOperator *op, const wmEvent *event) -{ - const bool snap = RNA_boolean_get(op->ptr, "snap"); - SK_Sketch *sketch = contextSketch(C, 0); - - if (sketch) { - SK_DrawData dd; - - sk_initDrawData(&dd, event->mval); - sk_getStrokePoint(C, &sketch->next_point, sketch, sketch->active_stroke, &dd, snap); - ED_area_tag_redraw(CTX_wm_area(C)); - } - - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; -} - -/* ============================================== Poll Functions ============================================= */ - -int ED_operator_sketch_mode_active_stroke(bContext *C) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - SK_Sketch *sketch = contextSketch(C, 0); - - if (ts->bone_sketching & BONE_SKETCHING && - sketch != NULL && - sketch->active_stroke != NULL) - { - return 1; - } - else { - return 0; - } -} - -static int ED_operator_sketch_mode_gesture(bContext *C) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - SK_Sketch *sketch = contextSketch(C, 0); - - if (ts->bone_sketching & BONE_SKETCHING && - (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0 && - sketch != NULL && - sketch->active_stroke == NULL) - { - return 1; - } - else { - return 0; - } -} - -int ED_operator_sketch_full_mode(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - ToolSettings *ts = CTX_data_tool_settings(C); - - if (obedit && - obedit->type == OB_ARMATURE && - ts->bone_sketching & BONE_SKETCHING && - (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0) - { - return 1; - } - else { - return 0; - } -} - -int ED_operator_sketch_mode(const bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - ToolSettings *ts = CTX_data_tool_settings(C); - - if (obedit && - obedit->type == OB_ARMATURE && - ts->bone_sketching & BONE_SKETCHING) - { - return 1; - } - else { - return 0; - } -} - -/* ================================================ Operators ================================================ */ - -void SKETCH_OT_delete(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Delete"; - ot->idname = "SKETCH_OT_delete"; - ot->description = "Delete a sketch stroke"; - - /* api callbacks */ - ot->invoke = sketch_delete; - - ot->poll = ED_operator_sketch_full_mode; - - /* flags */ -// ot->flag = OPTYPE_UNDO; -} - -void SKETCH_OT_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select"; - ot->idname = "SKETCH_OT_select"; - ot->description = "Select a sketch stroke"; - - /* api callbacks */ - ot->invoke = sketch_select; - - ot->poll = ED_operator_sketch_full_mode; - - /* flags */ -// ot->flag = OPTYPE_UNDO; -} - -void SKETCH_OT_cancel_stroke(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Cancel Stroke"; - ot->idname = "SKETCH_OT_cancel_stroke"; - ot->description = "Cancel the current sketch stroke"; - - /* api callbacks */ - ot->invoke = sketch_cancel_invoke; - - ot->poll = ED_operator_sketch_mode_active_stroke; - - /* flags */ -// ot->flag = OPTYPE_UNDO; -} - -void SKETCH_OT_convert(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Convert"; - ot->idname = "SKETCH_OT_convert"; - ot->description = "Convert the selected sketch strokes to bone chains"; - - /* api callbacks */ - ot->invoke = sketch_convert; - - ot->poll = ED_operator_sketch_full_mode; - - /* flags */ - ot->flag = OPTYPE_UNDO; -} - -void SKETCH_OT_finish_stroke(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "End Stroke"; - ot->idname = "SKETCH_OT_finish_stroke"; - ot->description = "End and keep the current sketch stroke"; - - /* api callbacks */ - ot->invoke = sketch_finish; - - ot->poll = ED_operator_sketch_mode_active_stroke; - - /* flags */ -// ot->flag = OPTYPE_UNDO; -} - -void SKETCH_OT_draw_preview(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Draw Preview"; - ot->idname = "SKETCH_OT_draw_preview"; - ot->description = "Draw preview of current sketch stroke (internal use)"; - - /* api callbacks */ - ot->invoke = sketch_draw_preview; - - ot->poll = ED_operator_sketch_mode_active_stroke; - - RNA_def_boolean(ot->srna, "snap", 0, "Snap", ""); - - /* flags */ -// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; -} - -void SKETCH_OT_draw_stroke(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Draw Stroke"; - ot->idname = "SKETCH_OT_draw_stroke"; - ot->description = "Start to draw a sketch stroke"; - - /* api callbacks */ - ot->invoke = sketch_draw_stroke; - ot->modal = sketch_draw_stroke_modal; - ot->cancel = sketch_draw_stroke_cancel; - - ot->poll = (int (*)(bContext *))ED_operator_sketch_mode; - - RNA_def_boolean(ot->srna, "snap", 0, "Snap", ""); - - /* flags */ - ot->flag = OPTYPE_BLOCKING; // OPTYPE_REGISTER|OPTYPE_UNDO -} - -void SKETCH_OT_gesture(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Gesture"; - ot->idname = "SKETCH_OT_gesture"; - ot->description = "Start to draw a gesture stroke"; - - /* api callbacks */ - ot->invoke = sketch_draw_gesture; - ot->modal = sketch_draw_gesture_modal; - ot->cancel = sketch_draw_gesture_cancel; - - ot->poll = ED_operator_sketch_mode_gesture; - - RNA_def_boolean(ot->srna, "snap", 0, "Snap", ""); - - /* flags */ - ot->flag = OPTYPE_BLOCKING; // OPTYPE_UNDO -} - diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index f27d68d0634..f6f97af32b9 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -27,25 +27,34 @@ * \ingroup edarmature */ +#include "MEM_guardedalloc.h" + + +#include "CLG_log.h" + #include "DNA_armature_types.h" #include "DNA_object_types.h" -#include "MEM_guardedalloc.h" - #include "BLI_math.h" #include "BLI_array_utils.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" +#include "BKE_layer.h" #include "BKE_undo_system.h" +#include "DEG_depsgraph.h" + #include "ED_armature.h" #include "ED_object.h" +#include "ED_undo.h" #include "ED_util.h" #include "WM_types.h" #include "WM_api.h" +/** We only need this locally. */ +static CLG_LogRef LOG = {"ed.undo.armature"}; + /* -------------------------------------------------------------------- */ /** \name Undo Conversion * \{ */ @@ -120,13 +129,20 @@ static Object *editarm_object_from_context(bContext *C) /* -------------------------------------------------------------------- */ /** \name Implements ED Undo System + * + * \note This is similar for all edit-mode types. * \{ */ -typedef struct ArmatureUndoStep { - UndoStep step; - /* note: will split out into list for multi-object-editmode. */ +typedef struct ArmatureUndoStep_Elem { + struct ArmatureUndoStep_Elem *next, *prev; UndoRefID_Object obedit_ref; UndoArmature data; +} ArmatureUndoStep_Elem; + +typedef struct ArmatureUndoStep { + UndoStep step; + ArmatureUndoStep_Elem *elems; + uint elems_len; } ArmatureUndoStep; static bool armature_undosys_poll(bContext *C) @@ -137,10 +153,24 @@ static bool armature_undosys_poll(bContext *C) static bool armature_undosys_step_encode(struct bContext *C, UndoStep *us_p) { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; - us->obedit_ref.ptr = editarm_object_from_context(C); - bArmature *arm = us->obedit_ref.ptr->data; - undoarm_from_editarm(&us->data, arm); - us->step.data_size = us->data.undo_size; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); + us->elems_len = objects_len; + + for (uint i = 0; i < objects_len; i++) { + Object *ob = objects[i]; + ArmatureUndoStep_Elem *elem = &us->elems[i]; + + elem->obedit_ref.ptr = ob; + bArmature *arm = elem->obedit_ref.ptr->data; + undoarm_from_editarm(&elem->data, arm); + us->step.data_size += elem->data.undo_size; + } + MEM_freeN(objects); return true; } @@ -151,24 +181,46 @@ static void armature_undosys_step_decode(struct bContext *C, UndoStep *us_p, int BLI_assert(armature_undosys_poll(C)); ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; - Object *obedit = us->obedit_ref.ptr; - bArmature *arm = obedit->data; - undoarm_to_editarm(&us->data, arm); - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + + for (uint i = 0; i < us->elems_len; i++) { + ArmatureUndoStep_Elem *elem = &us->elems[i]; + Object *obedit = elem->obedit_ref.ptr; + bArmature *arm = obedit->data; + if (arm->edbo == NULL) { + /* Should never fail, may not crash but can give odd behavior. */ + CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid", us_p->name, obedit->id.name); + continue; + } + undoarm_to_editarm(&elem->data, arm); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } + + /* The first element is always active */ + ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } static void armature_undosys_step_free(UndoStep *us_p) { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; - undoarm_free_data(&us->data); + + for (uint i = 0; i < us->elems_len; i++) { + ArmatureUndoStep_Elem *elem = &us->elems[i]; + undoarm_free_data(&elem->data); + } + MEM_freeN(us->elems); } static void armature_undosys_foreach_ID_ref( UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; - foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); + + for (uint i = 0; i < us->elems_len; i++) { + ArmatureUndoStep_Elem *elem = &us->elems[i]; + foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref)); + } } /* Export for ED_undo_sys. */ diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 4e31fcc7a11..bc6d776911a 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -46,6 +46,8 @@ #include "ED_mesh.h" #include "ED_armature.h" +#include "DEG_depsgraph.h" + #include "eigen_capi.h" #include "meshlaplacian.h" @@ -600,9 +602,10 @@ static float heat_limit_weight(float weight) return weight; } -void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, - bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, - float (*root)[3], float (*tip)[3], int *selected, const char **err_str) +void heat_bone_weighting( + Object *ob, Mesh *me, float (*verts)[3], int numsource, + bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, + float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; MLoopTri *mlooptri; @@ -830,7 +833,7 @@ typedef struct MeshDeformBind { int size, size3; /* meshes */ - DerivedMesh *cagedm; + Mesh *cagemesh; float (*cagecos)[3]; float (*vertexcos)[3]; int totvert, totcagevert; @@ -860,7 +863,7 @@ typedef struct MeshDeformBind { const MLoop *mloop; const MLoopTri *looptri; const float (*poly_nors)[3]; - } cagedm_cache; + } cagemesh_cache; } MeshDeformBind; typedef struct MeshDeformIsect { @@ -885,9 +888,9 @@ static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *r { struct MeshRayCallbackData *data = userdata; MeshDeformBind *mdb = data->mdb; - const MLoop *mloop = mdb->cagedm_cache.mloop; - const MLoopTri *looptri = mdb->cagedm_cache.looptri, *lt; - const float (*poly_nors)[3] = mdb->cagedm_cache.poly_nors; + const MLoop *mloop = mdb->cagemesh_cache.mloop; + const MLoopTri *looptri = mdb->cagemesh_cache.looptri, *lt; + const float (*poly_nors)[3] = mdb->cagemesh_cache.poly_nors; MeshDeformIsect *isec = data->isec; float no[3], co[3], dist; float *face[3]; @@ -951,9 +954,9 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const if (BLI_bvhtree_ray_cast_ex(mdb->bvhtree, isect_mdef.start, vec_normal, 0.0, &hit, harmonic_ray_callback, &data, BVH_RAYCAST_WATERTIGHT) != -1) { - const MLoop *mloop = mdb->cagedm_cache.mloop; - const MLoopTri *lt = &mdb->cagedm_cache.looptri[hit.index]; - const MPoly *mp = &mdb->cagedm_cache.mpoly[lt->poly]; + const MLoop *mloop = mdb->cagemesh_cache.mloop; + const MLoopTri *lt = &mdb->cagemesh_cache.looptri[hit.index]; + const MPoly *mp = &mdb->cagemesh_cache.mpoly[lt->poly]; const float (*cagecos)[3] = mdb->cagecos; const float len = isect_mdef.lambda; MDefBoundIsect *isect; @@ -1128,8 +1131,8 @@ static void meshdeform_bind_floodfill(MeshDeformBind *mdb) static float meshdeform_boundary_phi(const MeshDeformBind *mdb, const MDefBoundIsect *isect, int cagevert) { - const MLoop *mloop = mdb->cagedm_cache.mloop; - const MPoly *mp = &mdb->cagedm_cache.mpoly[isect->poly_index]; + const MLoop *mloop = mdb->cagemesh_cache.mloop; + const MPoly *mp = &mdb->cagemesh_cache.mpoly[isect->poly_index]; int i; for (i = 0; i < mp->totloop; i++) { @@ -1444,7 +1447,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi"); mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect"); mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound"); - mdb->bvhtree = bvhtree_from_mesh_get(&mdb->bvhdata, mdb->cagedm, BVHTREE_FROM_LOOPTRI, 4); + mdb->bvhtree = BKE_bvhtree_from_mesh_get(&mdb->bvhdata, mdb->cagemesh, BVHTREE_FROM_LOOPTRI, 4); mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside"); if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) @@ -1457,11 +1460,11 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa /* initialize data from 'cagedm' for reuse */ { - DerivedMesh *dm = mdb->cagedm; - mdb->cagedm_cache.mpoly = dm->getPolyArray(dm); - mdb->cagedm_cache.mloop = dm->getLoopArray(dm); - mdb->cagedm_cache.looptri = dm->getLoopTriArray(dm); - mdb->cagedm_cache.poly_nors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */ + Mesh *me = mdb->cagemesh; + mdb->cagemesh_cache.mpoly = me->mpoly; + mdb->cagemesh_cache.mloop = me->mloop; + mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me); + mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL); /* can be NULL */ } /* make bounding box equal size in all directions, add padding, and compute @@ -1573,7 +1576,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa } void ED_mesh_deform_bind_callback( - Scene *scene, MeshDeformModifierData *mmd, DerivedMesh *cagedm, + Scene *scene, MeshDeformModifierData *mmd, Mesh *cagemesh, float *vertexcos, int totvert, float cagemat[4][4]) { MeshDeformBind mdb; @@ -1589,12 +1592,12 @@ void ED_mesh_deform_bind_callback( mdb.vertexcos = MEM_callocN(sizeof(float) * 3 * totvert, "MeshDeformCos"); mdb.totvert = totvert; - mdb.cagedm = cagedm; - mdb.totcagevert = mdb.cagedm->getNumVerts(mdb.cagedm); + mdb.cagemesh = cagemesh; + mdb.totcagevert = mdb.cagemesh->totvert; mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.totcagevert, "MeshDeformBindCos"); copy_m4_m4(mdb.cagemat, cagemat); - mvert = mdb.cagedm->getVertArray(mdb.cagedm); + mvert = mdb.cagemesh->mvert; for (a = 0; a < mdb.totcagevert; a++) copy_v3_v3(mdb.cagecos[a], mvert[a].co); for (a = 0; a < mdb.totvert; a++) diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h index 202ac8e9b70..9c4ceacbee6 100644 --- a/source/blender/editors/armature/meshlaplacian.h +++ b/source/blender/editors/armature/meshlaplacian.h @@ -52,10 +52,11 @@ float laplacian_system_get_solution(LaplacianSystem *sys, int v); /* Heat Weighting */ -void heat_bone_weighting(struct Object *ob, struct Mesh *me, float (*verts)[3], - int numbones, struct bDeformGroup **dgrouplist, - struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], - int *selected, const char **error); +void heat_bone_weighting( + struct Object *ob, struct Mesh *me, float (*verts)[3], + int numbones, struct bDeformGroup **dgrouplist, + struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], + int *selected, const char **error); #ifdef RIGID_DEFORM /* As-Rigid-As-Possible Deformation */ diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index da328ee485f..fa9927419a0 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -31,6 +31,8 @@ * \ingroup edarmature */ +#include "MEM_guardedalloc.h" + #include "BLI_math.h" #include "BLI_blenlib.h" @@ -39,13 +41,16 @@ #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "BKE_action.h" #include "BKE_anim.h" #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_layer.h" + +#include "DEG_depsgraph.h" #include "RNA_access.h" #include "RNA_define.h" @@ -58,6 +63,7 @@ #include "ED_keyframing.h" #include "ED_screen.h" #include "ED_object.h" +#include "ED_view3d.h" #include "UI_interface.h" @@ -81,7 +87,7 @@ Object *ED_pose_object_from_context(bContext *C) } /* This function is used to process the necessary updates for */ -bool ED_object_posemode_enter_ex(Object *ob) +bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob) { BLI_assert(!ID_IS_LINKED(ob)); bool ok = false; @@ -90,6 +96,8 @@ bool ED_object_posemode_enter_ex(Object *ob) case OB_ARMATURE: ob->restore_mode = ob->mode; ob->mode |= OB_MODE_POSE; + /* Inform all CoW versions that we changed the mode. */ + DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE); ok = true; break; @@ -106,26 +114,31 @@ bool ED_object_posemode_enter(bContext *C, Object *ob) BKE_report(reports, RPT_WARNING, "Cannot pose libdata"); return false; } - bool ok = ED_object_posemode_enter_ex(ob); + struct Main *bmain = CTX_data_main(C); + bool ok = ED_object_posemode_enter_ex(bmain, ob); if (ok) { WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); } return ok; } -bool ED_object_posemode_exit_ex(Object *ob) +bool ED_object_posemode_exit_ex(struct Main *bmain, Object *ob) { bool ok = false; if (ob) { ob->restore_mode = ob->mode; ob->mode &= ~OB_MODE_POSE; + + /* Inform all CoW versions that we changed the mode. */ + DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE); ok = true; } return ok; } bool ED_object_posemode_exit(bContext *C, Object *ob) { - bool ok = ED_object_posemode_exit_ex(ob); + struct Main *bmain = CTX_data_main(C); + bool ok = ED_object_posemode_exit_ex(bmain, ob); if (ok) { WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); } @@ -167,8 +180,10 @@ static bool pose_has_protected_selected(Object *ob, short warn) * * To be called from various tools that do incremental updates */ -void ED_pose_recalculate_paths(Scene *scene, Object *ob) +void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob) { + struct Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); ListBase targets = {NULL, NULL}; /* set flag to force recalc, then grab the relevant bones to target */ @@ -176,8 +191,11 @@ void ED_pose_recalculate_paths(Scene *scene, Object *ob) animviz_get_object_motionpaths(ob, &targets); /* recalculate paths, then free */ - animviz_calc_motionpaths(scene, &targets); + animviz_calc_motionpaths(depsgraph, bmain, scene, &targets); BLI_freelistN(&targets); + + /* tag armature object for copy on write - so paths will draw/redraw */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } @@ -239,7 +257,7 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op) /* calculate the bones that now have motionpaths... */ /* TODO: only make for the selected bones? */ - ED_pose_recalculate_paths(scene, ob); + ED_pose_recalculate_paths(C, scene, ob); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); @@ -295,7 +313,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op)) /* calculate the bones that now have motionpaths... */ /* TODO: only make for the selected bones? */ - ED_pose_recalculate_paths(scene, ob); + ED_pose_recalculate_paths(C, scene, ob); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); @@ -593,7 +611,7 @@ static void pose_copy_menu(Scene *scene) BKE_pose_tag_recalc(bmain, ob->pose); } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations BIF_undo_push("Copy Pose Attributes"); @@ -604,34 +622,31 @@ static void pose_copy_menu(Scene *scene) static int pose_flip_names_exec(bContext *C, wmOperator *op) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm; - - /* paranoia checks */ - if (ELEM(NULL, ob, ob->pose)) - return OPERATOR_CANCELLED; - + ViewLayer *view_layer = CTX_data_view_layer(C); const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers"); - arm = ob->data; - - ListBase bones_names = {NULL}; - - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob) { - BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name)); - } - CTX_DATA_END; + bArmature *arm = ob->data; + ListBase bones_names = {NULL}; - ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers); + FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) + { + BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name)); + } + FOREACH_PCHAN_SELECTED_IN_OBJECT_END; - BLI_freelistN(&bones_names); + ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers); - /* since we renamed stuff... */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + BLI_freelistN(&bones_names); - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + /* since we renamed stuff... */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + } + FOREACH_OBJECT_IN_MODE_END; return OPERATOR_FINISHED; } @@ -679,7 +694,7 @@ static int pose_autoside_names_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* since we renamed stuff... */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); @@ -728,7 +743,7 @@ static int pose_bone_rotmode_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* notifiers and updates */ - DAG_id_tag_update((ID *)ob, OB_RECALC_DATA); + DEG_id_tag_update((ID *)ob, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); return OPERATOR_FINISHED; @@ -808,6 +823,7 @@ static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); /* done */ return OPERATOR_FINISHED; @@ -875,6 +891,7 @@ static int armature_layers_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -903,7 +920,7 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot) /* Present a popup to get the layers that should be used */ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ + int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ /* get layers that are active already */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) @@ -949,6 +966,7 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update((ID *)ob->data, DEG_TAG_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -1004,7 +1022,6 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven static int armature_bone_layers_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); - bArmature *arm = (ob) ? ob->data : NULL; PointerRNA ptr; int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ @@ -1012,7 +1029,7 @@ static int armature_bone_layers_exec(bContext *C, wmOperator *op) RNA_boolean_get_array(op->ptr, "layers", layers); /* set layers of pchans based on the values set in the operator props */ - CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) + CTX_DATA_BEGIN_WITH_ID (C, EditBone *, ebone, selected_editable_bones, bArmature *, arm) { /* get pointer for pchan, and write flags this way */ RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr); @@ -1048,55 +1065,54 @@ void ARMATURE_OT_bone_layers(wmOperatorType *ot) /* ********************************************** */ /* Show/Hide Bones */ -static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) +static int hide_pose_bone_fn(Object *ob, Bone *bone, void *ptr) { bArmature *arm = ob->data; - + const bool hide_select = (bool)GET_INT_FROM_POINTER(ptr); + int count = 0; if (arm->layer & bone->layer) { - if (bone->flag & BONE_SELECTED) { + if (((bone->flag & BONE_SELECTED) != 0) == hide_select) { bone->flag |= BONE_HIDDEN_P; + /* only needed when 'hide_select' is true, but harmless. */ bone->flag &= ~BONE_SELECTED; - if (arm->act_bone == bone) - arm->act_bone = NULL; - } - } - return 0; -} - -static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) -{ - bArmature *arm = ob->data; - - if (arm->layer & bone->layer) { - /* hrm... typo here? */ - if ((bone->flag & BONE_SELECTED) == 0) { - bone->flag |= BONE_HIDDEN_P; - if (arm->act_bone == bone) + if (arm->act_bone == bone) { arm->act_bone = NULL; + } + count += 1; } } - return 0; + return count; } /* active object is armature in posemode, poll checked */ static int pose_hide_exec(bContext *C, wmOperator *op) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = ob->data; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_object_pose_array_get_unique(view_layer, &objects_len); + bool changed_multi = false; - if (ob->proxy != NULL) { - BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected"); - } + const int hide_select = !RNA_boolean_get(op->ptr, "unselected"); + void *hide_select_p = SET_INT_IN_POINTER(hide_select); - if (RNA_boolean_get(op->ptr, "unselected")) - bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb); - else - bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + bArmature *arm = ob_iter->data; - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + if (ob_iter->proxy != NULL) { + BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected"); + } - return OPERATOR_FINISHED; + bool changed = bone_looper(ob_iter, arm->bonebase.first, hide_select_p, hide_pose_bone_fn) != 0; + if (changed) { + changed_multi = true; + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter); + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void POSE_OT_hide(wmOperatorType *ot) @@ -1122,32 +1138,44 @@ static int show_pose_bone_cb(Object *ob, Bone *bone, void *data) const bool select = GET_INT_FROM_POINTER(data); bArmature *arm = ob->data; - + int count = 0; if (arm->layer & bone->layer) { if (bone->flag & BONE_HIDDEN_P) { if (!(bone->flag & BONE_UNSELECTABLE)) { SET_FLAG_FROM_TEST(bone->flag, select, BONE_SELECTED); } bone->flag &= ~BONE_HIDDEN_P; + count += 1; } } - return 0; + return count; } /* active object is armature in posemode, poll checked */ static int pose_reveal_exec(bContext *C, wmOperator *op) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = ob->data; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_object_pose_array_get_unique(view_layer, &objects_len); + bool changed_multi = false; const bool select = RNA_boolean_get(op->ptr, "select"); + void *select_p = SET_INT_IN_POINTER(select); - bone_looper(ob, arm->bonebase.first, SET_INT_IN_POINTER(select), show_pose_bone_cb); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + bArmature *arm = ob_iter->data; - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + bool changed = bone_looper(ob_iter, arm->bonebase.first, select_p, show_pose_bone_cb); + if (changed) { + changed_multi = true; + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter); + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + } + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void POSE_OT_reveal(wmOperatorType *ot) @@ -1173,27 +1201,34 @@ void POSE_OT_reveal(wmOperatorType *ot) static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID); - /* loop through all selected pchans, flipping and keying (as needed) */ - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) - { - /* only if bone is using quaternion rotation */ - if (pchan->rotmode == ROT_MODE_QUAT) { - /* quaternions have 720 degree range */ - negate_v4(pchan->quat); + bool changed_multi = false; - ED_autokeyframe_pchan(C, scene, ob, pchan, ks); - } - } - CTX_DATA_END; + ViewLayer *view_layer = CTX_data_view_layer(C); + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter) { + bool changed = false; + /* loop through all selected pchans, flipping and keying (as needed) */ + FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) { + /* only if bone is using quaternion rotation */ + if (pchan->rotmode == ROT_MODE_QUAT) { + changed = true; + /* quaternions have 720 degree range */ + negate_v4(pchan->quat); - /* notifiers and updates */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); + ED_autokeyframe_pchan(C, scene, ob_iter, pchan, ks); + } + } FOREACH_PCHAN_SELECTED_IN_OBJECT_END; - return OPERATOR_FINISHED; + if (changed) { + changed_multi = true; + /* notifiers and updates */ + DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter); + } + } FOREACH_OBJECT_IN_MODE_END; + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void POSE_OT_quaternions_flip(wmOperatorType *ot) @@ -1211,3 +1246,34 @@ void POSE_OT_quaternions_flip(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* -------------------------------------------------------------------- */ +/** \name Toggle Bone selection Overlay Operator + * \{ */ + +static int toggle_bone_selection_exec(bContext *C, wmOperator *UNUSED(op)) +{ + View3D *v3d = CTX_wm_view3d(C); + v3d->overlay.flag ^= V3D_OVERLAY_BONE_SELECTION; + ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + return OPERATOR_FINISHED; +} + +static int pose_select_linked_poll(bContext *C) +{ + return (ED_operator_view3d_active(C) && ED_operator_posemode(C)); +} + +void POSE_OT_toggle_bone_selection_overlay(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Bone Selection Overlay"; + ot->description = "Toggle bone selection overlay of the viewport"; + ot->idname = "POSE_OT_toggle_bone_selection_overlay"; + + /* api callbacks */ + ot->exec = toggle_bone_selection_exec; + ot->poll = pose_select_linked_poll; +} + +/** \} */ diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 9648bb99c05..aefca13d66c 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -38,9 +38,12 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" +#include "BKE_armature.h" #include "BKE_action.h" #include "BKE_context.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -104,6 +107,7 @@ static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op)) /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -204,15 +208,16 @@ static int pose_group_assign_exec(bContext *C, wmOperator *op) BKE_pose_add_group(ob->pose, NULL); /* add selected bones to group then */ - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) + FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) { pchan->agrp_index = pose->active_group; done = true; } - CTX_DATA_END; + FOREACH_PCHAN_SELECTED_IN_OBJECT_END; /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); /* report done status */ if (done) @@ -251,17 +256,18 @@ static int pose_group_unassign_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* find selected bones to remove from all bone groups */ - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) + FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) { if (pchan->agrp_index) { pchan->agrp_index = 0; done = true; } } - CTX_DATA_END; + FOREACH_PCHAN_SELECTED_IN_OBJECT_END; /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); /* report done status */ if (done) @@ -413,6 +419,7 @@ static int group_sort_exec(bContext *C, wmOperator *UNUSED(op)) /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -432,11 +439,11 @@ void POSE_OT_group_sort(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static void pose_group_select(bContext *C, Object *ob, bool select) +static void pose_group_select(Object *ob, bool select) { bPose *pose = ob->pose; - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) + FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob, pchan) { if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) { if (select) { @@ -449,7 +456,7 @@ static void pose_group_select(bContext *C, Object *ob, bool select) } } } - CTX_DATA_END; + FOREACH_PCHAN_VISIBLE_IN_OBJECT_END; } static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op)) @@ -460,7 +467,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op)) if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; - pose_group_select(C, ob, 1); + pose_group_select(ob, 1); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); @@ -491,7 +498,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; - pose_group_select(C, ob, 0); + pose_group_select(ob, 0); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index fd5db84873b..02a1e22dbba 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -46,7 +46,6 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" @@ -55,6 +54,8 @@ #include "BKE_context.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -500,6 +501,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op) /* store new 'active' pose number */ act->active_marker = BLI_listbase_count(&act->markers); + DEG_id_tag_update(&act->id, DEG_TAG_COPY_ON_WRITE); /* done */ return OPERATOR_FINISHED; @@ -614,6 +616,7 @@ static int poselib_remove_exec(bContext *C, wmOperator *op) * may be being shown in anim editors as active action */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + DEG_id_tag_update(&act->id, DEG_TAG_COPY_ON_WRITE); /* done */ return OPERATOR_FINISHED; @@ -1101,9 +1104,9 @@ static void poselib_preview_apply(bContext *C, wmOperator *op) */ // FIXME: shouldn't this use the builtin stuff? if ((pld->arm->flag & ARM_DELAYDEFORM) == 0) - DAG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */ + DEG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */ else - BKE_pose_where_is(pld->scene, pld->ob); + BKE_pose_where_is(CTX_data_depsgraph(C), pld->scene, pld->ob); } /* do header print - if interactively previewing */ @@ -1609,9 +1612,9 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op) * - note: code copied from transform_generics.c -> recalcData() */ if ((arm->flag & ARM_DELAYDEFORM) == 0) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ else - BKE_pose_where_is(scene, ob); + BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob); } else if (pld->state == PL_PREVIEW_CONFIRM) { /* tag poses as appropriate */ @@ -1622,14 +1625,14 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op) action_set_activemarker(act, marker, NULL); /* Update event for pose and deformation children */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* updates */ if (IS_AUTOKEY_MODE(scene, NORMAL)) { //remake_action_ipos(ob->action); } else - BKE_pose_where_is(scene, ob); + BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob); } /* Request final redraw of the view. */ diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 1389b26a1e1..75fd952b52a 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -43,9 +43,11 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_layer.h" + +#include "DEG_depsgraph.h" #include "RNA_access.h" #include "RNA_define.h" @@ -122,18 +124,21 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) * (see rna_Bone_select_update() in rna_armature.c for details) */ if (arm->flag & ARM_HAS_VIZ_DEPS) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } /* send necessary notifiers */ WM_main_add_notifier(NC_GEOM | ND_DATA, ob); + + /* tag armature for copy-on-write update (since act_bone is in armature not object) */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); } } /* called from editview.c, for mode-less pose selection */ /* assumes scene obact and basact is still on old situation */ bool ED_armature_pose_select_pick_with_buffer( - Scene *scene, Base *base, const unsigned int *buffer, short hits, + ViewLayer *view_layer, Base *base, const unsigned int *buffer, short hits, bool extend, bool deselect, bool toggle, bool do_nearest) { Object *ob = base->object; @@ -141,11 +146,15 @@ bool ED_armature_pose_select_pick_with_buffer( if (!ob || !ob->pose) return 0; - nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1, do_nearest); + Object *ob_act = OBACT(view_layer); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + + /* Callers happen to already get the active base */ + Base *base_dummy = NULL; + nearBone = get_bone_from_selectbuffer(&base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy); /* if the bone cannot be affected, don't do anything */ if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) { - Object *ob_act = OBACT; bArmature *arm = ob->data; /* since we do unified select, we don't shift+select a bone if the @@ -163,7 +172,12 @@ bool ED_armature_pose_select_pick_with_buffer( } if (!extend && !deselect && !toggle) { - ED_pose_deselect_all(ob, SEL_DESELECT, true); + { + uint objects_len = 0; + Object **objects = BKE_object_pose_array_get_unique(view_layer, &objects_len); + ED_pose_deselect_all_multi(objects, objects_len, SEL_DESELECT, true); + MEM_freeN(objects); + } nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_bone = nearBone; } @@ -197,7 +211,7 @@ bool ED_armature_pose_select_pick_with_buffer( if (ob_act->mode & OB_MODE_WEIGHT_PAINT) { if (nearBone == arm->act_bone) { ED_vgroup_select_by_name(ob_act, nearBone->name); - DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA); } } /* if there are some dependencies for visualizing armature state @@ -207,8 +221,11 @@ bool ED_armature_pose_select_pick_with_buffer( /* NOTE: ob not ob_act here is intentional - it's the source of the * bones being selected [T37247] */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } + + /* tag armature for copy-on-write update (since act_bone is in armature not object) */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); } } @@ -249,6 +266,58 @@ void ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil } } +static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility) +{ + bArmature *arm = ob->data; + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) { + return true; + } + } + } + return false; +} + +static bool ed_pose_is_any_selected_multi(Object **objects, uint objects_len, bool ignore_visibility) +{ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) { + return true; + } + } + return false; +} + +void ED_pose_deselect_all_multi(Object **objects, uint objects_len, int select_mode, const bool ignore_visibility) +{ + if (select_mode == SEL_TOGGLE) { + select_mode = ed_pose_is_any_selected_multi( + objects, objects_len, ignore_visibility) ? SEL_DESELECT : SEL_SELECT; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + bArmature *arm = ob_iter->data; + + ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility); + + /* if there are some dependencies for visualizing armature state + * (e.g. Mask Modifier in 'Armature' mode), force update + */ + if (arm->flag & ARM_HAS_VIZ_DEPS) { + /* NOTE: ob not ob_act here is intentional - it's the source of the + * bones being selected [T37247] + */ + DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA); + } + + /* need to tag armature for cow updates, or else selection doesn't update */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + } +} + /* ***************** Selections ********************** */ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend) @@ -259,9 +328,6 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend) if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE)) return; - /* XXX old cruft! use notifiers instead */ - //select_actionchannel_by_name (ob->action, bone->name, !(shift)); - if (extend) bone->flag &= ~BONE_SELECTED; else @@ -275,18 +341,19 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend) /* previously known as "selectconnected_posearmature" */ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = (bArmature *)ob->data; Bone *bone, *curBone, *next = NULL; const bool extend = RNA_boolean_get(op->ptr, "extend"); view3d_operator_needs_opengl(C); - bone = get_nearest_bone(C, event->mval, !extend); + Base *base = NULL; + bone = get_nearest_bone(C, event->mval, !extend, &base); if (!bone) return OPERATOR_CANCELLED; + bArmature *arm = base->object->data; + /* Select parents */ for (curBone = bone; curBone; curBone = next) { /* ignore bone if cannot be selected */ @@ -307,16 +374,19 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve /* Select children */ for (curBone = bone->childbase.first; curBone; curBone = next) - selectconnected_posebonechildren(ob, curBone, extend); + selectconnected_posebonechildren(base->object, curBone, extend); /* updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); if (arm->flag & ARM_HAS_VIZ_DEPS) { /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); } + /* need to tag armature for cow updates, or else selection doesn't update */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + return OPERATOR_FINISHED; } @@ -332,7 +402,7 @@ void POSE_OT_select_linked(wmOperatorType *ot) ot->idname = "POSE_OT_select_linked"; ot->description = "Select bones related to selected ones by parent/child relationships"; - /* api callbacks */ + /* callbacks */ /* leave 'exec' unset */ ot->invoke = pose_select_connected_invoke; ot->poll = pose_select_linked_poll; @@ -351,28 +421,34 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op) int action = RNA_enum_get(op->ptr, "action"); Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_context(C); - bArmature *arm = ob->data; int multipaint = scene->toolsettings->multipaint; if (action == SEL_TOGGLE) { action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT; } + Object *ob_prev = NULL; + /* Set the flags */ - CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) + CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) { + bArmature *arm = ob->data; pose_do_bone_select(pchan, action); + + if (ob_prev != ob) { + /* weightpaint or mask modifiers need depsgraph updates */ + if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + /* need to tag armature for cow updates, or else selection doesn't update */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + ob_prev = ob; + } } CTX_DATA_END; WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL); - /* weightpaint or mask modifiers need depsgraph updates */ - if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - return OPERATOR_FINISHED; } @@ -397,33 +473,44 @@ void POSE_OT_select_all(wmOperatorType *ot) static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = (bArmature *)ob->data; - bPoseChannel *pchan, *parent; - - /* Determine if there is an active bone */ - pchan = CTX_data_active_pose_bone(C); - if (pchan) { - parent = pchan->parent; - if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) { - parent->bone->flag |= BONE_SELECTED; - arm->act_bone = parent->bone; - } - else { - return OPERATOR_CANCELLED; - } - } - else { - return OPERATOR_CANCELLED; - } + /* only clear relevant transforms for selected bones */ + ViewLayer *view_layer = CTX_data_view_layer(C); + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter) + { + Object *ob = ob_iter; + bArmature *arm = (bArmature *)ob->data; - /* updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) + { + if (pchan) { + bPoseChannel *parent = pchan->parent; + if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) { + parent->bone->flag |= BONE_SELECTED; + arm->act_bone = parent->bone; + } + else { + continue; + } + } + else { + continue; + } - if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + /* updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + + if (arm->flag & ARM_HAS_VIZ_DEPS) { + /* mask modifier ('armature' mode), etc. */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + + /* tag armature for copy-on-write update (since act_bone is in armature not object) */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + + } + FOREACH_PCHAN_SELECTED_IN_OBJECT_END; } + FOREACH_OBJECT_IN_MODE_END; return OPERATOR_FINISHED; } @@ -447,13 +534,13 @@ void POSE_OT_select_parent(wmOperatorType *ot) static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = (bArmature *)ob->data; bConstraint *con; int found = 0; + Object *ob_prev = NULL; - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) + CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) { + bArmature *arm = ob->data; if (pchan->bone->flag & BONE_SELECTED) { for (con = pchan->constraints.first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); @@ -469,6 +556,18 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) { pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; found = 1; + + if (ob != ob_prev) { + /* updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + if (arm->flag & ARM_HAS_VIZ_DEPS) { + /* mask modifier ('armature' mode), etc. */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + /* tag armature for copy on write, since selection status is armature data */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + ob_prev = ob; + } } } } @@ -484,14 +583,6 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op if (!found) return OPERATOR_CANCELLED; - /* updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - return OPERATOR_FINISHED; } @@ -583,9 +674,12 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) if (arm->flag & ARM_HAS_VIZ_DEPS) { /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } + /* tag armature for copy-on-write update (since act_bone is in armature not object) */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + return OPERATOR_FINISHED; } @@ -828,9 +922,12 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op) if (arm->flag & ARM_HAS_VIZ_DEPS) { /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } + /* need to tag armature for cow updates, or else selection doesn't update */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + /* report done status */ if (changed) return OPERATOR_FINISHED; @@ -873,59 +970,63 @@ void POSE_OT_select_grouped(wmOperatorType *ot) static int pose_select_mirror_exec(bContext *C, wmOperator *op) { Object *ob_act = CTX_data_active_object(C); - Object *ob = BKE_object_pose_armature_get(ob_act); - bArmature *arm; - bPoseChannel *pchan, *pchan_mirror_act = NULL; - const bool active_only = RNA_boolean_get(op->ptr, "only_active"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); + ViewLayer *view_layer = CTX_data_view_layer(C); - if ((ob && (ob->mode & OB_MODE_POSE)) == 0) { - return OPERATOR_CANCELLED; - } - - arm = ob->data; + FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, OB_MODE_POSE, ob) + { + bArmature *arm; + bPoseChannel *pchan, *pchan_mirror_act = NULL; + const bool active_only = RNA_boolean_get(op->ptr, "only_active"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - const int flag = (pchan->bone->flag & BONE_SELECTED); - PBONE_PREV_FLAG_SET(pchan, flag); - } + arm = ob->data; - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_SELECTABLE(arm, pchan->bone)) { - bPoseChannel *pchan_mirror; - int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0; + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + const int flag = (pchan->bone->flag & BONE_SELECTED); + PBONE_PREV_FLAG_SET(pchan, flag); + } - if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) && - (PBONE_VISIBLE(arm, pchan_mirror->bone))) - { - const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror); - flag_new |= flag_mirror; + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if (PBONE_SELECTABLE(arm, pchan->bone)) { + bPoseChannel *pchan_mirror; + int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0; + + if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) && + (PBONE_VISIBLE(arm, pchan_mirror->bone))) + { + const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror); + flag_new |= flag_mirror; + + if (pchan->bone == arm->act_bone) { + pchan_mirror_act = pchan_mirror; + } - if (pchan->bone == arm->act_bone) { - pchan_mirror_act = pchan_mirror; + /* skip all but the active or its mirror */ + if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) { + continue; + } } - /* skip all but the active or its mirror */ - if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) { - continue; - } + pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new; } - - pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new; } - } - if (pchan_mirror_act) { - arm->act_bone = pchan_mirror_act->bone; + if (pchan_mirror_act) { + arm->act_bone = pchan_mirror_act->bone; - /* in weightpaint we select the associated vertex group too */ - if (ob_act->mode & OB_MODE_WEIGHT_PAINT) { - ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name); - DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA); + /* in weightpaint we select the associated vertex group too */ + if (ob_act->mode & OB_MODE_WEIGHT_PAINT) { + ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name); + DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA); + } } - } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + + /* need to tag armature for cow updates, or else selection doesn't update */ + DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE); + } + FOREACH_OBJECT_IN_MODE_END; return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 1fc623eb6af..de0612d840d 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -45,13 +45,16 @@ #include "BKE_blender_copybuffer.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_main.h" #include "BKE_object.h" +#include "BKE_layer.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -70,12 +73,14 @@ /* Pose Apply */ /* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */ -static void applyarmature_fix_boneparents(Scene *scene, Object *armob) +static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Object *armob) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); Object workob, *ob; /* go through all objects in database */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* if parent is bone in this armature, apply corrections */ if ((ob->parent == armob) && (ob->partype == PARBONE)) { /* apply current transform from parent (not yet destroyed), @@ -83,7 +88,7 @@ static void applyarmature_fix_boneparents(Scene *scene, Object *armob) */ BKE_object_apply_mat4(ob, ob->obmat, false, false); - BKE_object_workob_calc_parent(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } } @@ -92,8 +97,10 @@ static void applyarmature_fix_boneparents(Scene *scene, Object *armob) /* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object + const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); bArmature *arm = BKE_armature_from_object(ob); bPose *pose; bPoseChannel *pchan; @@ -121,11 +128,12 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) pose = ob->pose; for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); /* simply copy the head/tail values from pchan over to curbone */ - copy_v3_v3(curbone->head, pchan->pose_head); - copy_v3_v3(curbone->tail, pchan->pose_tail); + copy_v3_v3(curbone->head, pchan_eval->pose_head); + copy_v3_v3(curbone->tail, pchan_eval->pose_tail); /* fix roll: * 1. find auto-calculated roll value for this bone now @@ -141,7 +149,7 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) invert_m3_m3(imat, premat); /* get pchan 'visual' matrix */ - copy_m3_m4(pmat, pchan->pose_mat); + copy_m3_m4(pmat, pchan_eval->pose_mat); /* remove auto from visual and get euler rotation */ mul_m3_m3m3(tmat, imat, pmat); @@ -155,17 +163,19 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) * then clear the pchan values (so we don't get a double-up) */ if (pchan->bone->segments > 1) { - curbone->curveInX += pchan->curveInX; - curbone->curveInY += pchan->curveInY; - curbone->curveOutX += pchan->curveOutX; - curbone->curveOutY += pchan->curveOutY; - curbone->roll1 += pchan->roll1; - curbone->roll2 += pchan->roll2; - curbone->ease1 += pchan->ease1; - curbone->ease2 += pchan->ease2; - curbone->scaleIn += pchan->scaleIn; - curbone->scaleOut += pchan->scaleOut; - + /* combine rest/pose values */ + curbone->curveInX += pchan_eval->curveInX; + curbone->curveInY += pchan_eval->curveInY; + curbone->curveOutX += pchan_eval->curveOutX; + curbone->curveOutY += pchan_eval->curveOutY; + curbone->roll1 += pchan_eval->roll1; + curbone->roll2 += pchan_eval->roll2; + curbone->ease1 += pchan_eval->ease1; + curbone->ease2 += pchan_eval->ease2; + curbone->scaleIn += pchan_eval->scaleIn; + curbone->scaleOut += pchan_eval->scaleOut; + + /* reset pose values */ pchan->curveInX = pchan->curveOutX = 0.0f; pchan->curveInY = pchan->curveOutY = 0.0f; pchan->roll1 = pchan->roll2 = 0.0f; @@ -189,13 +199,14 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) ED_armature_edit_free(arm); /* flush positions of posebones */ - BKE_pose_where_is(scene, ob); + BKE_pose_where_is(depsgraph, scene, ob); /* fix parenting of objects which are bone-parented */ - applyarmature_fix_boneparents(scene, ob); + applyarmature_fix_boneparents(C, scene, ob); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -219,38 +230,41 @@ void POSE_OT_armature_apply(wmOperatorType *ot) /* set the current pose as the restpose */ static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object - - /* don't check if editmode (should be done by caller) */ - if (ob->type != OB_ARMATURE) - return OPERATOR_CANCELLED; + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); - /* loop over all selected pchans - * - * TODO, loop over children before parents if multiple bones - * at once are to be predictable*/ - CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) + FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, OB_MODE_POSE, ob) { - float delta_mat[4][4]; - - /* chan_mat already contains the delta transform from rest pose to pose-mode pose - * as that is baked into there so that B-Bones will work. Once we've set this as the - * new raw-transform components, don't recalc the poses yet, otherwise IK result will - * change, thus changing the result we may be trying to record. - */ - /* XXX For some reason, we can't use pchan->chan_mat here, gives odd rotation/offset (see T38251). - * Using pchan->pose_mat and bringing it back in bone space seems to work as expected! - */ - BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, delta_mat); + /* loop over all selected pchans + * + * TODO, loop over children before parents if multiple bones + * at once are to be predictable*/ + FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) + { + const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); + float delta_mat[4][4]; + + /* chan_mat already contains the delta transform from rest pose to pose-mode pose + * as that is baked into there so that B-Bones will work. Once we've set this as the + * new raw-transform components, don't recalc the poses yet, otherwise IK result will + * change, thus changing the result we may be trying to record. + */ + /* XXX For some reason, we can't use pchan->chan_mat here, gives odd rotation/offset (see T38251). + * Using pchan->pose_mat and bringing it back in bone space seems to work as expected! + */ + BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, delta_mat); - BKE_pchan_apply_mat4(pchan, delta_mat, true); - } - CTX_DATA_END; + BKE_pchan_apply_mat4(pchan, delta_mat, true); + } + FOREACH_PCHAN_SELECTED_IN_OBJECT_END; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + } + FOREACH_OBJECT_IN_MODE_END; return OPERATOR_FINISHED; } @@ -565,11 +579,11 @@ static int pose_paste_exec(bContext *C, wmOperator *op) BKE_main_free(tmp_bmain); /* Update event for pose and deformation children. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* Recalculate paths if any of the bones have paths... */ if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) { - ED_pose_recalculate_paths(scene, ob); + ED_pose_recalculate_paths(C, scene, ob); } /* Notifiers for updates, */ @@ -754,8 +768,7 @@ static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op, void (*clear_func)(bPoseChannel *), const char default_ksName[]) { Scene *scene = CTX_data_scene(C); - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - short autokey = 0; + bool changed_multi = false; /* sanity checks */ if (ELEM(NULL, clear_func, default_ksName)) { @@ -764,47 +777,70 @@ static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op, } /* only clear relevant transforms for selected bones */ - CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) + ViewLayer *view_layer = CTX_data_view_layer(C); + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter) { - /* run provided clearing function */ - clear_func(pchan); + Object *ob_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), ob_iter); // XXX: UGLY HACK (for autokey + clear transforms) + ListBase dsources = {NULL, NULL}; + bool changed = false; - /* do auto-keyframing as appropriate */ - if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* clear any unkeyed tags */ - if (pchan->bone) - pchan->bone->flag &= ~BONE_UNKEYED; + FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) + { + /* run provided clearing function */ + clear_func(pchan); + changed = true; + + /* do auto-keyframing as appropriate */ + if (autokeyframe_cfra_can_key(scene, &ob_iter->id)) { + /* clear any unkeyed tags */ + if (pchan->bone) { + pchan->bone->flag &= ~BONE_UNKEYED; + } + /* tag for autokeying later */ + ANIM_relative_keyingset_add_source(&dsources, &ob_iter->id, &RNA_PoseBone, pchan); - /* tag for autokeying later */ - autokey = 1; - } - else { - /* add unkeyed tags */ - if (pchan->bone) - pchan->bone->flag |= BONE_UNKEYED; +#if 1 /* XXX: Ugly Hack - Run clearing function on evaluated copy of pchan */ + bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); + clear_func(pchan_eval); +#endif + } + else { + /* add unkeyed tags */ + if (pchan->bone) { + pchan->bone->flag |= BONE_UNKEYED; + } + } } - } - CTX_DATA_END; + FOREACH_PCHAN_SELECTED_IN_OBJECT_END; - /* perform autokeying on the bones if needed */ - if (autokey) { - /* get KeyingSet to use */ - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName); + if (changed) { + changed_multi = true; - /* insert keyframes */ - ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + /* perform autokeying on the bones if needed */ + if (!BLI_listbase_is_empty(&dsources)) { + /* get KeyingSet to use */ + KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName); - /* now recalculate paths */ - if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) - ED_pose_recalculate_paths(scene, ob); - } + /* insert keyframes */ + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + /* now recalculate paths */ + if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) { + ED_pose_recalculate_paths(C, scene, ob_iter); + } - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); + BLI_freelistN(&dsources); + } - return OPERATOR_FINISHED; + DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA); + + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter); + } + } + FOREACH_OBJECT_IN_MODE_END; + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } /* --------------- */ @@ -897,57 +933,61 @@ void POSE_OT_transforms_clear(wmOperatorType *ot) static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op) { + ViewLayer *view_layer = CTX_data_view_layer(C); Scene *scene = CTX_data_scene(C); - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); float cframe = (float)CFRA; const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); - if ((ob->adt) && (ob->adt->action)) { - /* XXX: this is just like this to avoid contaminating anything else; - * just pose values should change, so this should be fine - */ - bPose *dummyPose = NULL; - Object workob = {{NULL}}; - bPoseChannel *pchan; + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob) + { + if ((ob->adt) && (ob->adt->action)) { + /* XXX: this is just like this to avoid contaminating anything else; + * just pose values should change, so this should be fine + */ + bPose *dummyPose = NULL; + Object workob = {{NULL}}; + bPoseChannel *pchan; - /* execute animation step for current frame using a dummy copy of the pose */ - BKE_pose_copy_data(&dummyPose, ob->pose, 0); + /* execute animation step for current frame using a dummy copy of the pose */ + BKE_pose_copy_data(&dummyPose, ob->pose, 0); - BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name)); - workob.type = OB_ARMATURE; - workob.data = ob->data; - workob.adt = ob->adt; - workob.pose = dummyPose; + BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name)); + workob.type = OB_ARMATURE; + workob.data = ob->data; + workob.adt = ob->adt; + workob.pose = dummyPose; - BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(NULL, scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM); - /* copy back values, but on selected bones only */ - for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { - pose_bone_do_paste(ob, pchan, only_select, 0); - } + /* copy back values, but on selected bones only */ + for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { + pose_bone_do_paste(ob, pchan, only_select, 0); + } - /* free temp data - free manually as was copied without constraints */ - for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->prop) { - IDP_FreeProperty(pchan->prop); - MEM_freeN(pchan->prop); + /* free temp data - free manually as was copied without constraints */ + for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->prop) { + IDP_FreeProperty(pchan->prop); + MEM_freeN(pchan->prop); + } } + + /* was copied without constraints */ + BLI_freelistN(&dummyPose->chanbase); + MEM_freeN(dummyPose); + } + else { + /* no animation, so just reset whole pose to rest pose + * (cannot just restore for selected though) + */ + BKE_pose_rest(ob->pose); } - /* was copied without constraints */ - BLI_freelistN(&dummyPose->chanbase); - MEM_freeN(dummyPose); - } - else { - /* no animation, so just reset whole pose to rest pose - * (cannot just restore for selected though) - */ - BKE_pose_rest(ob->pose); + /* notifiers and updates */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); } - - /* notifiers and updates */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); + FOREACH_OBJECT_IN_MODE_END; return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 84eaa5b02bd..b64c8528010 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -39,11 +39,12 @@ #include "BKE_action.h" #include "BKE_armature.h" -#include "BKE_depsgraph.h" #include "BKE_idprop.h" #include "BKE_context.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "WM_api.h" @@ -182,6 +183,7 @@ void poseAnim_mapping_free(ListBase *pfLinks) /* helper for apply() / reset() - refresh the data */ void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); bArmature *arm = (bArmature *)ob->data; /* old optimize trick... this enforces to bypass the depgraph @@ -189,11 +191,11 @@ void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob) */ /* FIXME: shouldn't this use the builtin stuff? */ if ((arm->flag & ARM_DELAYDEFORM) == 0) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ else - BKE_pose_where_is(scene, ob); + BKE_pose_where_is(depsgraph, scene, ob); - /* note, notifier might evolve */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); /* otherwise animation doesn't get updated */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); } @@ -266,7 +268,7 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, Object *ob, ListBa */ if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) { //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear - ED_pose_recalculate_paths(scene, ob); + ED_pose_recalculate_paths(C, scene, ob); } } } diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c deleted file mode 100644 index d837c702cb7..00000000000 --- a/source/blender/editors/armature/reeb.c +++ /dev/null @@ -1,3435 +0,0 @@ -/* - * ***** 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): Martin Poirier - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/armature/reeb.c - * \ingroup edarmature - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_edgehash.h" -#include "BLI_ghash.h" - -#include "BKE_context.h" - -#include "reeb.h" - -#if 0 /* UNUSED 2.5 */ -static ReebGraph *GLOBAL_RG = NULL; -static ReebGraph *FILTERED_RG = NULL; -#endif - -/* - * Skeleton generation algorithm based on: - * "Harmonic Skeleton for Realistic Character Animation" - * Gregoire Aujay, Franck Hetroy, Francis Lazarus and Christine Depraz - * SIGGRAPH 2007 - * - * Reeb graph generation algorithm based on: - * "Robust On-line Computation of Reeb Graphs: Simplicity and Speed" - * Valerio Pascucci, Giorgio Scorzelli, Peer-Timo Bremer and Ajith Mascarenhas - * SIGGRAPH 2007 - * - * */ - -#if 0 -#define DEBUG_REEB -#define DEBUG_REEB_NODE -#endif - -/* place-holders! */ -typedef struct EditEdge { - void *fake; -} EditEdge; - -typedef struct EditFace { - void *fake; -} EditFace; -/* end place-holders! */ - -typedef struct VertexData { - float w; /* weight */ - int i; /* index */ - ReebNode *n; -} VertexData; - -typedef struct EdgeIndex { - EditEdge **edges; - int *offset; -} EdgeIndex; - -typedef enum { - MERGE_LOWER, - MERGE_HIGHER, - MERGE_APPEND -} MergeDirection; - -int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1); -void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction); -int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1); -EditEdge *NextEdgeForVert(EdgeIndex *indexed_edges, int index); -void mergeArcFaces(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc); -void addFacetoArc(ReebArc *arc, EditFace *efa); - -void REEB_RadialSymmetry(BNode *root_node, RadialArc *ring, int count); -void REEB_AxialSymmetry(BNode *root_node, BNode *node1, BNode *node2, struct BArc *barc1, BArc *barc2); - -void flipArcBuckets(ReebArc *arc); - - -/***************************************** UTILS **********************************************/ - -#if 0 /* UNUSED */ -static VertexData *allocVertexData(EditMesh *em) -{ - VertexData *data; - EditVert *eve; - int totvert, index; - - totvert = BLI_listbase_count(&em->verts); - - data = MEM_callocN(sizeof(VertexData) * totvert, "VertexData"); - - for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) - { - data[index].i = index; - data[index].w = 0; - eve->tmp.p = data + index; - } - - return data; -} - -static int indexData(EditVert *eve) -{ - return ((VertexData *)eve->tmp.p)->i; -} - -static float weightData(EditVert *eve) -{ - return ((VertexData *)eve->tmp.p)->w; -} - -static void weightSetData(EditVert *eve, float w) -{ - ((VertexData *)eve->tmp.p)->w = w; -} - -static ReebNode *nodeData(EditVert *eve) -{ - return ((VertexData *)eve->tmp.p)->n; -} - -static void nodeSetData(EditVert *eve, ReebNode *n) -{ - ((VertexData *)eve->tmp.p)->n = n; -} - -#endif - -void REEB_freeArc(BArc *barc) -{ - ReebArc *arc = (ReebArc *)barc; - BLI_freelistN(&arc->edges); - - if (arc->buckets) - MEM_freeN(arc->buckets); - - if (arc->faces) - BLI_ghash_free(arc->faces, NULL, NULL); - - MEM_freeN(arc); -} - -void REEB_freeGraph(ReebGraph *rg) -{ - ReebArc *arc; - ReebNode *node; - - // free nodes - for (node = rg->nodes.first; node; node = node->next) { - BLI_freeNode((BGraph *)rg, (BNode *)node); - } - BLI_freelistN(&rg->nodes); - - // free arcs - arc = rg->arcs.first; - while (arc) { - ReebArc *next = arc->next; - REEB_freeArc((BArc *)arc); - arc = next; - } - - // free edge map - BLI_edgehash_free(rg->emap, NULL); - - /* free linked graph */ - if (rg->link_up) { - REEB_freeGraph(rg->link_up); - } - - MEM_freeN(rg); -} - -ReebGraph *newReebGraph(void) -{ - ReebGraph *rg; - rg = MEM_callocN(sizeof(ReebGraph), "reeb graph"); - - rg->totnodes = 0; - rg->emap = BLI_edgehash_new(__func__); - - - rg->free_arc = REEB_freeArc; - rg->free_node = NULL; - rg->radial_symmetry = REEB_RadialSymmetry; - rg->axial_symmetry = REEB_AxialSymmetry; - - return rg; -} - -void BIF_flagMultiArcs(ReebGraph *rg, int flag) -{ - for (; rg; rg = rg->link_up) { - BLI_flagArcs((BGraph *)rg, flag); - } -} - -#if 0 /* UNUSED */ -static ReebNode *addNode(ReebGraph *rg, EditVert *eve) -{ - float weight; - ReebNode *node = NULL; - - weight = weightData(eve); - - node = MEM_callocN(sizeof(ReebNode), "reeb node"); - - node->flag = 0; // clear flag on init - node->symmetry_level = 0; - node->arcs = NULL; - node->degree = 0; - node->weight = weight; - node->index = rg->totnodes; - copy_v3_v3(node->p, eve->co); - - BLI_addtail(&rg->nodes, node); - rg->totnodes++; - - nodeSetData(eve, node); - - return node; -} - -static ReebNode *copyNode(ReebGraph *rg, ReebNode *node) -{ - ReebNode *cp_node = NULL; - - cp_node = MEM_callocN(sizeof(ReebNode), "reeb node copy"); - - memcpy(cp_node, node, sizeof(ReebNode)); - - cp_node->prev = NULL; - cp_node->next = NULL; - cp_node->arcs = NULL; - - cp_node->link_up = NULL; - cp_node->link_down = NULL; - - BLI_addtail(&rg->nodes, cp_node); - rg->totnodes++; - - return cp_node; -} - -static void relinkNodes(ReebGraph *low_rg, ReebGraph *high_rg) -{ - ReebNode *low_node, *high_node; - - if (low_rg == NULL || high_rg == NULL) - { - return; - } - - for (low_node = low_rg->nodes.first; low_node; low_node = low_node->next) - { - for (high_node = high_rg->nodes.first; high_node; high_node = high_node->next) - { - if (low_node->index == high_node->index) - { - high_node->link_down = low_node; - low_node->link_up = high_node; - break; - } - } - } -} -#endif - -ReebNode *BIF_otherNodeFromIndex(ReebArc *arc, ReebNode *node) -{ - return (arc->head->index == node->index) ? arc->tail : arc->head; -} - -ReebNode *BIF_NodeFromIndex(ReebArc *arc, ReebNode *node) -{ - return (arc->head->index == node->index) ? arc->head : arc->tail; -} - -ReebNode *BIF_lowestLevelNode(ReebNode *node) -{ - while (node->link_down) { - node = node->link_down; - } - - return node; -} - -#if 0 /* UNUSED */ -static ReebArc *copyArc(ReebGraph *rg, ReebArc *arc) -{ - ReebArc *cp_arc; - ReebNode *node; - - cp_arc = MEM_callocN(sizeof(ReebArc), "reeb arc copy"); - - memcpy(cp_arc, arc, sizeof(ReebArc)); - - cp_arc->link_up = arc; - - cp_arc->head = NULL; - cp_arc->tail = NULL; - - cp_arc->prev = NULL; - cp_arc->next = NULL; - - cp_arc->edges.first = NULL; - cp_arc->edges.last = NULL; - - /* copy buckets */ - cp_arc->buckets = MEM_callocN(sizeof(EmbedBucket) * cp_arc->bcount, "embed bucket"); - memcpy(cp_arc->buckets, arc->buckets, sizeof(EmbedBucket) * cp_arc->bcount); - - /* copy faces map */ - cp_arc->faces = BLI_ghash_ptr_new("copyArc gh"); - mergeArcFaces(rg, cp_arc, arc); - - /* find corresponding head and tail */ - for (node = rg->nodes.first; node && (cp_arc->head == NULL || cp_arc->tail == NULL); node = node->next) - { - if (node->index == arc->head->index) - { - cp_arc->head = node; - } - else if (node->index == arc->tail->index) - { - cp_arc->tail = node; - } - } - - BLI_addtail(&rg->arcs, cp_arc); - - return cp_arc; -} - -static ReebGraph *copyReebGraph(ReebGraph *rg, int level) -{ - ReebNode *node; - ReebArc *arc; - ReebGraph *cp_rg = newReebGraph(); - - cp_rg->resolution = rg->resolution; - cp_rg->length = rg->length; - cp_rg->link_up = rg; - cp_rg->multi_level = level; - - /* Copy nodes */ - for (node = rg->nodes.first; node; node = node->next) - { - ReebNode *cp_node = copyNode(cp_rg, node); - cp_node->multi_level = level; - } - - /* Copy arcs */ - for (arc = rg->arcs.first; arc; arc = arc->next) - { - copyArc(cp_rg, arc); - } - - BLI_buildAdjacencyList((BGraph *)cp_rg); - - return cp_rg; -} -#endif - -ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node) -{ - ReebGraph *multi_rg = rg; - - while (multi_rg && multi_rg->multi_level != node->multi_level) { - multi_rg = multi_rg->link_up; - } - - return multi_rg; -} - -#if 0 /* UNUSED */ -static ReebEdge *copyEdge(ReebEdge *edge) -{ - ReebEdge *newEdge = NULL; - - newEdge = MEM_callocN(sizeof(ReebEdge), "reeb edge"); - memcpy(newEdge, edge, sizeof(ReebEdge)); - - newEdge->next = NULL; - newEdge->prev = NULL; - - return newEdge; -} - -static void printArc(ReebArc *arc) -{ - ReebEdge *edge; - ReebNode *head = (ReebNode *)arc->head; - ReebNode *tail = (ReebNode *)arc->tail; - printf("arc: (%i) %f -> (%i) %f\n", head->index, head->weight, tail->index, tail->weight); - - for (edge = arc->edges.first; edge; edge = edge->next) - { - printf("\tedge (%i, %i)\n", edge->v1->index, edge->v2->index); - } -} - -static void flipArc(ReebArc *arc) -{ - ReebNode *tmp; - tmp = arc->head; - arc->head = arc->tail; - arc->tail = tmp; - - flipArcBuckets(arc); -} - -#ifdef DEBUG_REEB_NODE -static void NodeDegreeDecrement(ReebGraph *UNUSED(rg), ReebNode *node) -{ - node->degree--; - -// if (node->degree == 0) -// { -// printf("would remove node %i\n", node->index); -// } -} - -static void NodeDegreeIncrement(ReebGraph *UNUSED(rg), ReebNode *node) -{ -// if (node->degree == 0) -// { -// printf("first connect node %i\n", node->index); -// } - - node->degree++; -} - -#else -# define NodeDegreeDecrement(rg, node) {node->degree--; } (void)0 -# define NodeDegreeIncrement(rg, node) {node->degree++; } (void)0 -#endif - -void repositionNodes(ReebGraph *rg) -{ - BArc *arc = NULL; - BNode *node = NULL; - - // Reset node positions - for (node = rg->nodes.first; node; node = node->next) { - node->p[0] = node->p[1] = node->p[2] = 0; - } - - for (arc = rg->arcs.first; arc; arc = arc->next) { - if (((ReebArc *)arc)->bcount > 0) { - float p[3]; - - copy_v3_v3(p, ((ReebArc *)arc)->buckets[0].p); - mul_v3_fl(p, 1.0f / arc->head->degree); - add_v3_v3(arc->head->p, p); - - copy_v3_v3(p, ((ReebArc *)arc)->buckets[((ReebArc *)arc)->bcount - 1].p); - mul_v3_fl(p, 1.0f / arc->tail->degree); - add_v3_v3(arc->tail->p, p); - } - } -} - -void verifyNodeDegree(ReebGraph *rg) -{ -#ifdef DEBUG_REEB - ReebNode *node = NULL; - ReebArc *arc = NULL; - - for (node = rg->nodes.first; node; node = node->next) { - int count = 0; - for (arc = rg->arcs.first; arc; arc = arc->next) { - if (arc->head == node || arc->tail == node) { - count++; - } - } - if (count != node->degree) { - printf("degree error in node %i: expected %i got %i\n", node->index, count, node->degree); - } - if (node->degree == 0) { - printf("zero degree node %i with weight %f\n", node->index, node->weight); - } - } -#endif -} - -static void verifyBucketsArc(ReebGraph *UNUSED(rg), ReebArc *arc) -{ - ReebNode *head = (ReebNode *)arc->head; - ReebNode *tail = (ReebNode *)arc->tail; - - if (arc->bcount > 0) { - int i; - for (i = 0; i < arc->bcount; i++) { - if (arc->buckets[i].nv == 0) { - printArc(arc); - printf("count error in bucket %i/%i\n", i + 1, arc->bcount); - } - } - - if (ceilf(head->weight) != arc->buckets[0].val) { - printArc(arc); - printf("alloc error in first bucket: %f should be %f\n", arc->buckets[0].val, ceil(head->weight)); - } - if (floorf(tail->weight) != arc->buckets[arc->bcount - 1].val) { - printArc(arc); - printf("alloc error in last bucket: %f should be %f\n", arc->buckets[arc->bcount - 1].val, floor(tail->weight)); - } - } -} - -void verifyBuckets(ReebGraph *rg) -{ -#ifdef DEBUG_REEB - ReebArc *arc = NULL; - for (arc = rg->arcs.first; arc; arc = arc->next) { - verifyBucketsArc(rg, arc); - } -#endif -} - -void verifyFaces(ReebGraph *rg) -{ -#ifdef DEBUG_REEB - int total = 0; - ReebArc *arc = NULL; - for (arc = rg->arcs.first; arc; arc = arc->next) { - total += BLI_ghash_len(arc->faces); - } - -#endif -} - -void verifyArcs(ReebGraph *rg) -{ - ReebArc *arc; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - if (arc->head->weight > arc->tail->weight) { - printf("FLIPPED ARC!\n"); - } - } -} - -static void verifyMultiResolutionLinks(ReebGraph *rg, int level) -{ -#ifdef DEBUG_REEB - ReebGraph *lower_rg = rg->link_up; - - if (lower_rg) { - ReebArc *arc; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - if (BLI_findindex(&lower_rg->arcs, arc->link_up) == -1) { - printf("missing arc %p for level %i\n", (void *)arc->link_up, level); - printf("Source arc was ---\n"); - printArc(arc); - - arc->link_up = NULL; - } - } - - - verifyMultiResolutionLinks(lower_rg, level + 1); - } -#endif -} -/***************************************** BUCKET UTILS **********************************************/ - -static void addVertToBucket(EmbedBucket *b, float co[3]) -{ - b->nv++; - interp_v3_v3v3(b->p, b->p, co, 1.0f / b->nv); -} - -#if 0 /* UNUSED 2.5 */ -static void removeVertFromBucket(EmbedBucket *b, float co[3]) -{ - mul_v3_fl(b->p, (float)b->nv); - sub_v3_v3(b->p, co); - b->nv--; - mul_v3_fl(b->p, 1.0f / (float)b->nv); -} -#endif - -static void mergeBuckets(EmbedBucket *bDst, EmbedBucket *bSrc) -{ - if (bDst->nv > 0 && bSrc->nv > 0) { - bDst->nv += bSrc->nv; - interp_v3_v3v3(bDst->p, bDst->p, bSrc->p, (float)bSrc->nv / (float)(bDst->nv)); - } - else if (bSrc->nv > 0) { - bDst->nv = bSrc->nv; - copy_v3_v3(bDst->p, bSrc->p); - } -} - -static void mergeArcBuckets(ReebArc *aDst, ReebArc *aSrc, float start, float end) -{ - if (aDst->bcount > 0 && aSrc->bcount > 0) { - int indexDst = 0, indexSrc = 0; - - start = max_fff(start, aDst->buckets[0].val, aSrc->buckets[0].val); - - while (indexDst < aDst->bcount && aDst->buckets[indexDst].val < start) { - indexDst++; - } - - while (indexSrc < aSrc->bcount && aSrc->buckets[indexSrc].val < start) { - indexSrc++; - } - - for (; indexDst < aDst->bcount && - indexSrc < aSrc->bcount && - aDst->buckets[indexDst].val <= end && - aSrc->buckets[indexSrc].val <= end - - ; indexDst++, indexSrc++) - { - mergeBuckets(aDst->buckets + indexDst, aSrc->buckets + indexSrc); - } - } -} - -void flipArcBuckets(ReebArc *arc) -{ - int i, j; - - for (i = 0, j = arc->bcount - 1; i < j; i++, j--) { - EmbedBucket tmp; - - tmp = arc->buckets[i]; - arc->buckets[i] = arc->buckets[j]; - arc->buckets[j] = tmp; - } -} - -static int countArcBuckets(ReebArc *arc) -{ - return (int)(floor(arc->tail->weight) - ceil(arc->head->weight)) + 1; -} - -static void allocArcBuckets(ReebArc *arc) -{ - int i; - float start = ceil(arc->head->weight); - arc->bcount = countArcBuckets(arc); - - if (arc->bcount > 0) { - arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "embed bucket"); - - for (i = 0; i < arc->bcount; i++) { - arc->buckets[i].val = start + i; - } - } - else { - arc->buckets = NULL; - } -} - -static void resizeArcBuckets(ReebArc *arc) -{ - EmbedBucket *oldBuckets = arc->buckets; - int oldBCount = arc->bcount; - - if (countArcBuckets(arc) == oldBCount) { - return; - } - - allocArcBuckets(arc); - - if (oldBCount != 0 && arc->bcount != 0) { - int oldStart = (int)oldBuckets[0].val; - int oldEnd = (int)oldBuckets[oldBCount - 1].val; - int newStart = (int)arc->buckets[0].val; - int newEnd = (int)arc->buckets[arc->bcount - 1].val; - int oldOffset = 0; - int newOffset = 0; - int len; - - if (oldStart < newStart) { - oldOffset = newStart - oldStart; - } - else { - newOffset = oldStart - newStart; - } - - len = MIN2(oldEnd - (oldStart + oldOffset) + 1, newEnd - (newStart - newOffset) + 1); - - memcpy(arc->buckets + newOffset, oldBuckets + oldOffset, len * sizeof(EmbedBucket)); - } - - if (oldBuckets != NULL) { - MEM_freeN(oldBuckets); - } -} - -static void reweightBuckets(ReebArc *arc) -{ - int i; - float start = ceil((arc->head)->weight); - - if (arc->bcount > 0) { - for (i = 0; i < arc->bcount; i++) { - arc->buckets[i].val = start + i; - } - } -} - -static void interpolateBuckets(ReebArc *arc, float *start_p, float *end_p, int start_index, int end_index) -{ - int total; - int j; - - total = end_index - start_index + 2; - - for (j = start_index; j <= end_index; j++) { - EmbedBucket *empty = arc->buckets + j; - empty->nv = 1; - interp_v3_v3v3(empty->p, start_p, end_p, (float)(j - start_index + 1) / total); - } -} - -static void fillArcEmptyBuckets(ReebArc *arc) -{ - float *start_p, *end_p; - int start_index = 0, end_index = 0; - int missing = 0; - int i; - - start_p = arc->head->p; - - for (i = 0; i < arc->bcount; i++) { - EmbedBucket *bucket = arc->buckets + i; - - if (missing) { - if (bucket->nv > 0) { - missing = 0; - - end_p = bucket->p; - end_index = i - 1; - - interpolateBuckets(arc, start_p, end_p, start_index, end_index); - } - } - else { - if (bucket->nv == 0) { - missing = 1; - - if (i > 0) { - start_p = arc->buckets[i - 1].p; - } - start_index = i; - } - } - } - - if (missing) { - end_p = arc->tail->p; - end_index = arc->bcount - 1; - - interpolateBuckets(arc, start_p, end_p, start_index, end_index); - } -} - -static void ExtendArcBuckets(ReebArc *arc) -{ - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - EmbedBucket *last_bucket, *first_bucket; - float *previous = NULL; - float average_length = 0, length; - int padding_head = 0, padding_tail = 0; - - if (arc->bcount == 0) { - return; /* failsafe, shouldn't happen */ - } - - initArcIterator(iter, arc, arc->head); - IT_next(iter); - previous = iter->p; - - for (IT_next(iter); - IT_stopped(iter) == 0; - previous = iter->p, IT_next(iter) - ) - { - average_length += len_v3v3(previous, iter->p); - } - average_length /= (arc->bcount - 1); - - first_bucket = arc->buckets; - last_bucket = arc->buckets + (arc->bcount - 1); - - length = len_v3v3(first_bucket->p, arc->head->p); - if (length > 2 * average_length) { - padding_head = (int)floor(length / average_length); - } - - length = len_v3v3(last_bucket->p, arc->tail->p); - if (length > 2 * average_length) { - padding_tail = (int)floor(length / average_length); - } - - if (padding_head + padding_tail > 0) { - EmbedBucket *old_buckets = arc->buckets; - - arc->buckets = MEM_callocN(sizeof(EmbedBucket) * (padding_head + arc->bcount + padding_tail), "embed bucket"); - memcpy(arc->buckets + padding_head, old_buckets, arc->bcount * sizeof(EmbedBucket)); - - arc->bcount = padding_head + arc->bcount + padding_tail; - - MEM_freeN(old_buckets); - } - - if (padding_head > 0) { - interpolateBuckets(arc, arc->head->p, first_bucket->p, 0, padding_head); - } - - if (padding_tail > 0) { - interpolateBuckets(arc, last_bucket->p, arc->tail->p, arc->bcount - padding_tail, arc->bcount - 1); - } -} - -/* CALL THIS ONLY AFTER FILTERING, SINCE IT MESSES UP WEIGHT DISTRIBUTION */ -static void extendGraphBuckets(ReebGraph *rg) -{ - ReebArc *arc; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - ExtendArcBuckets(arc); - } -} - -/**************************************** LENGTH CALCULATIONS ****************************************/ - -static void calculateArcLength(ReebArc *arc) -{ - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - float *vec0, *vec1; - - arc->length = 0; - - initArcIterator(iter, arc, arc->head); - - vec0 = arc->head->p; - vec1 = arc->head->p; /* in case there's no embedding */ - - while (IT_next(iter)) { - vec1 = iter->p; - - arc->length += len_v3v3(vec0, vec1); - - vec0 = vec1; - } - - arc->length += len_v3v3(arc->tail->p, vec1); -} - -static void calculateGraphLength(ReebGraph *rg) -{ - ReebArc *arc; - - for (arc = rg->arcs.first; arc; arc = arc->next) { - calculateArcLength(arc); - } -} -#endif - -/**************************************** SYMMETRY HANDLING ******************************************/ - -void REEB_RadialSymmetry(BNode *root_node, RadialArc *ring, int count) -{ - ReebNode *node = (ReebNode *)root_node; - float axis[3]; - int i; - - copy_v3_v3(axis, root_node->symmetry_axis); - - /* first pass, merge incrementally */ - for (i = 0; i < count - 1; i++) { - ReebNode *node1, *node2; - ReebArc *arc1, *arc2; - float tangent[3]; - float normal[3]; - int j = i + 1; - - add_v3_v3v3(tangent, ring[i].n, ring[j].n); - cross_v3_v3v3(normal, tangent, axis); - - node1 = (ReebNode *)BLI_otherNode(ring[i].arc, root_node); - node2 = (ReebNode *)BLI_otherNode(ring[j].arc, root_node); - - arc1 = (ReebArc *)ring[i].arc; - arc2 = (ReebArc *)ring[j].arc; - - /* mirror first node and mix with the second */ - BLI_mirrorAlongAxis(node1->p, root_node->p, normal); - interp_v3_v3v3(node2->p, node2->p, node1->p, 1.0f / (j + 1)); - - /* Merge buckets - * there shouldn't be any null arcs here, but just to be safe - * */ - if (arc1->bcount > 0 && arc2->bcount > 0) { - ReebArcIterator arc_iter1, arc_iter2; - BArcIterator *iter1 = (BArcIterator *)&arc_iter1; - BArcIterator *iter2 = (BArcIterator *)&arc_iter2; - EmbedBucket *bucket1 = NULL, *bucket2 = NULL; - - initArcIterator(iter1, arc1, (ReebNode *)root_node); - initArcIterator(iter2, arc2, (ReebNode *)root_node); - - bucket1 = IT_next(iter1); - bucket2 = IT_next(iter2); - - /* Make sure they both start at the same value */ - while (bucket1 && bucket2 && bucket1->val < bucket2->val) { - bucket1 = IT_next(iter1); - } - - while (bucket1 && bucket2 && bucket2->val < bucket1->val) { - bucket2 = IT_next(iter2); - } - - - for (; bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) { - bucket2->nv += bucket1->nv; /* add counts */ - - /* mirror on axis */ - BLI_mirrorAlongAxis(bucket1->p, root_node->p, normal); - /* add bucket2 in bucket1 */ - interp_v3_v3v3(bucket2->p, bucket2->p, bucket1->p, (float)bucket1->nv / (float)(bucket2->nv)); - } - } - } - - /* second pass, mirror back on previous arcs */ - for (i = count - 1; i > 0; i--) { - ReebNode *node1, *node2; - ReebArc *arc1, *arc2; - float tangent[3]; - float normal[3]; - int j = i - 1; - - add_v3_v3v3(tangent, ring[i].n, ring[j].n); - cross_v3_v3v3(normal, tangent, axis); - - node1 = (ReebNode *)BLI_otherNode(ring[i].arc, root_node); - node2 = (ReebNode *)BLI_otherNode(ring[j].arc, root_node); - - arc1 = (ReebArc *)ring[i].arc; - arc2 = (ReebArc *)ring[j].arc; - - /* copy first node than mirror */ - copy_v3_v3(node2->p, node1->p); - BLI_mirrorAlongAxis(node2->p, root_node->p, normal); - - /* Copy buckets - * there shouldn't be any null arcs here, but just to be safe - * */ - if (arc1->bcount > 0 && arc2->bcount > 0) { - ReebArcIterator arc_iter1, arc_iter2; - BArcIterator *iter1 = (BArcIterator *)&arc_iter1; - BArcIterator *iter2 = (BArcIterator *)&arc_iter2; - EmbedBucket *bucket1 = NULL, *bucket2 = NULL; - - initArcIterator(iter1, arc1, node); - initArcIterator(iter2, arc2, node); - - bucket1 = IT_next(iter1); - bucket2 = IT_next(iter2); - - /* Make sure they both start at the same value */ - while (bucket1 && bucket1->val < bucket2->val) { - bucket1 = IT_next(iter1); - } - - while (bucket2 && bucket2->val < bucket1->val) { - bucket2 = IT_next(iter2); - } - - - for (; bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) { - /* copy and mirror back to bucket2 */ - bucket2->nv = bucket1->nv; - copy_v3_v3(bucket2->p, bucket1->p); - BLI_mirrorAlongAxis(bucket2->p, node->p, normal); - } - } - } -} - -void REEB_AxialSymmetry(BNode *root_node, BNode *node1, BNode *node2, struct BArc *barc1, BArc *barc2) -{ - ReebArc *arc1, *arc2; - float nor[3], p[3]; - - arc1 = (ReebArc *)barc1; - arc2 = (ReebArc *)barc2; - - copy_v3_v3(nor, root_node->symmetry_axis); - - /* mirror node2 along axis */ - copy_v3_v3(p, node2->p); - BLI_mirrorAlongAxis(p, root_node->p, nor); - - /* average with node1 */ - add_v3_v3(node1->p, p); - mul_v3_fl(node1->p, 0.5f); - - /* mirror back on node2 */ - copy_v3_v3(node2->p, node1->p); - BLI_mirrorAlongAxis(node2->p, root_node->p, nor); - - /* Merge buckets - * there shouldn't be any null arcs here, but just to be safe - * */ - if (arc1->bcount > 0 && arc2->bcount > 0) { - ReebArcIterator arc_iter1, arc_iter2; - BArcIterator *iter1 = (BArcIterator *)&arc_iter1; - BArcIterator *iter2 = (BArcIterator *)&arc_iter2; - EmbedBucket *bucket1 = NULL, *bucket2 = NULL; - - initArcIterator(iter1, arc1, (ReebNode *)root_node); - initArcIterator(iter2, arc2, (ReebNode *)root_node); - - bucket1 = IT_next(iter1); - bucket2 = IT_next(iter2); - - /* Make sure they both start at the same value */ - while (bucket1 && bucket1->val < bucket2->val) { - bucket1 = IT_next(iter1); - } - - while (bucket2 && bucket2->val < bucket1->val) { - bucket2 = IT_next(iter2); - } - - - for (; bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) { - bucket1->nv += bucket2->nv; /* add counts */ - - /* mirror on axis */ - BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor); - /* add bucket2 in bucket1 */ - interp_v3_v3v3(bucket1->p, bucket1->p, bucket2->p, (float)bucket2->nv / (float)(bucket1->nv)); - - /* copy and mirror back to bucket2 */ - bucket2->nv = bucket1->nv; - copy_v3_v3(bucket2->p, bucket1->p); - BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor); - } - } -} - -/************************************** ADJACENCY LIST *************************************************/ - - -/****************************************** SMOOTHING **************************************************/ - -#if 0 /* UNUSED */ -void postprocessGraph(ReebGraph *rg, char mode) -{ - ReebArc *arc; - float fac1 = 0, fac2 = 1, fac3 = 0; - - switch (mode) - { - case SKGEN_AVERAGE: - fac1 = fac2 = fac3 = 1.0f / 3.0f; - break; - case SKGEN_SMOOTH: - fac1 = fac3 = 0.25f; - fac2 = 0.5f; - break; - case SKGEN_SHARPEN: - fac1 = fac3 = -0.25f; - fac2 = 1.5f; - break; - default: -// XXX -// error("Unknown post processing mode"); - return; - } - - for (arc = rg->arcs.first; arc; arc = arc->next) - { - EmbedBucket *buckets = arc->buckets; - int bcount = arc->bcount; - int index; - - for (index = 1; index < bcount - 1; index++) - { - interp_v3_v3v3(buckets[index].p, buckets[index].p, buckets[index - 1].p, fac1 / (fac1 + fac2)); - interp_v3_v3v3(buckets[index].p, buckets[index].p, buckets[index + 1].p, fac3 / (fac1 + fac2 + fac3)); - } - } -} - -/********************************************SORTING****************************************************/ - -static int compareNodesWeight(void *vnode1, void *vnode2) -{ - ReebNode *node1 = (ReebNode *)vnode1; - ReebNode *node2 = (ReebNode *)vnode2; - - if (node1->weight < node2->weight) - { - return -1; - } - if (node1->weight > node2->weight) - { - return 1; - } - else { - return 0; - } -} - -void sortNodes(ReebGraph *rg) -{ - BLI_listbase_sort(&rg->nodes, compareNodesWeight); -} - -static int compareArcsWeight(void *varc1, void *varc2) -{ - ReebArc *arc1 = (ReebArc *)varc1; - ReebArc *arc2 = (ReebArc *)varc2; - ReebNode *node1 = (ReebNode *)arc1->head; - ReebNode *node2 = (ReebNode *)arc2->head; - - if (node1->weight < node2->weight) - { - return -1; - } - if (node1->weight > node2->weight) - { - return 1; - } - else { - return 0; - } -} - -void sortArcs(ReebGraph *rg) -{ - BLI_listbase_sort(&rg->arcs, compareArcsWeight); -} -/******************************************* JOINING ***************************************************/ - -static void reweightArc(ReebGraph *rg, ReebArc *arc, ReebNode *start_node, float start_weight) -{ - ReebNode *node; - float old_weight; - float end_weight = start_weight + ABS(arc->tail->weight - arc->head->weight); - int i; - - node = (ReebNode *)BLI_otherNode((BArc *)arc, (BNode *)start_node); - - /* prevent backtracking */ - if (node->flag == 1) - { - return; - } - - if (arc->tail == start_node) - { - flipArc(arc); - } - - start_node->flag = 1; - - for (i = 0; i < node->degree; i++) - { - ReebArc *next_arc = node->arcs[i]; - - reweightArc(rg, next_arc, node, end_weight); - } - - /* update only if needed */ - if (arc->head->weight != start_weight || arc->tail->weight != end_weight) - { - old_weight = arc->head->weight; /* backup head weight, other arcs need it intact, it will be fixed by the source arc */ - - arc->head->weight = start_weight; - arc->tail->weight = end_weight; - - reweightBuckets(arc); - resizeArcBuckets(arc); - fillArcEmptyBuckets(arc); - - arc->head->weight = old_weight; - } -} - -static void reweightSubgraph(ReebGraph *rg, ReebNode *start_node, float start_weight) -{ - int i; - - BLI_flagNodes((BGraph *)rg, 0); - - for (i = 0; i < start_node->degree; i++) - { - ReebArc *next_arc = start_node->arcs[i]; - - reweightArc(rg, next_arc, start_node, start_weight); - } - start_node->weight = start_weight; -} - -static int joinSubgraphsEnds(ReebGraph *rg, float threshold, int nb_subgraphs) -{ - int joined = 0; - int subgraph; - - for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++) - { - ReebNode *start_node, *end_node; - ReebNode *min_node_start = NULL, *min_node_end = NULL; - float min_distance = FLT_MAX; - - for (start_node = rg->nodes.first; start_node; start_node = start_node->next) - { - if (start_node->subgraph_index == subgraph && start_node->degree == 1) - { - - for (end_node = rg->nodes.first; end_node; end_node = end_node->next) - { - if (end_node->subgraph_index != subgraph) - { - float distance = len_v3v3(start_node->p, end_node->p); - - if (distance < threshold && distance < min_distance) - { - min_distance = distance; - min_node_end = end_node; - min_node_start = start_node; - } - } - } - } - } - - end_node = min_node_end; - start_node = min_node_start; - - if (end_node && start_node) - { - ReebArc *start_arc /* , *end_arc */ /* UNUSED */; - int merging = 0; - - start_arc = start_node->arcs[0]; - /* end_arc = end_node->arcs[0]; */ /* UNUSED */ - - if (start_arc->tail == start_node) - { - reweightSubgraph(rg, end_node, start_node->weight); - - start_arc->tail = end_node; - - merging = 1; - } - else if (start_arc->head == start_node) - { - reweightSubgraph(rg, start_node, end_node->weight); - - start_arc->head = end_node; - - merging = 2; - } - - if (merging) - { - BLI_ReflagSubgraph((BGraph *)rg, end_node->flag, subgraph); - - resizeArcBuckets(start_arc); - fillArcEmptyBuckets(start_arc); - - NodeDegreeIncrement(rg, end_node); - BLI_rebuildAdjacencyListForNode((BGraph *)rg, (BNode *)end_node); - - BLI_removeNode((BGraph *)rg, (BNode *)start_node); - } - - joined = 1; - } - } - - return joined; -} - -/* Reweight graph from smallest node, fix fliped arcs */ -static void fixSubgraphsOrientation(ReebGraph *rg, int nb_subgraphs) -{ - int subgraph; - - for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++) - { - ReebNode *node; - ReebNode *start_node = NULL; - - for (node = rg->nodes.first; node; node = node->next) - { - if (node->subgraph_index == subgraph) - { - if (start_node == NULL || node->weight < start_node->weight) - { - start_node = node; - } - } - } - - if (start_node) - { - reweightSubgraph(rg, start_node, start_node->weight); - } - } -} - -static int joinSubgraphs(ReebGraph *rg, float threshold) -{ - int nb_subgraphs; - int joined = 0; - - BLI_buildAdjacencyList((BGraph *)rg); - - if (BLI_isGraphCyclic((BGraph *)rg)) { - /* don't deal with cyclic graphs YET */ - return 0; - } - - /* sort nodes before flagging subgraphs to make sure root node is subgraph 0 */ - sortNodes(rg); - - nb_subgraphs = BLI_FlagSubgraphs((BGraph *)rg); - - /* Harmonic function can create flipped arcs, take the occasion to fix them */ -// XXX -// if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC) -// { - fixSubgraphsOrientation(rg, nb_subgraphs); -// } - - if (nb_subgraphs > 1) - { - joined |= joinSubgraphsEnds(rg, threshold, nb_subgraphs); - - if (joined) - { - removeNormalNodes(rg); - BLI_buildAdjacencyList((BGraph *)rg); - } - } - - return joined; -} - -/****************************************** FILTERING **************************************************/ - -static float lengthArc(ReebArc *arc) -{ -#if 0 - ReebNode *head = (ReebNode *)arc->head; - ReebNode *tail = (ReebNode *)arc->tail; - - return tail->weight - head->weight; -#else - return arc->length; -#endif -} - -static int compareArcs(void *varc1, void *varc2) -{ - ReebArc *arc1 = (ReebArc *)varc1; - ReebArc *arc2 = (ReebArc *)varc2; - float len1 = lengthArc(arc1); - float len2 = lengthArc(arc2); - - if (len1 < len2) { - return -1; - } - if (len1 > len2) { - return 1; - } - else { - return 0; - } -} - -static void filterArc(ReebGraph *rg, ReebNode *newNode, ReebNode *removedNode, ReebArc *srcArc, int merging) -{ - ReebArc *arc = NULL, *nextArc = NULL; - - if (merging) { - /* first pass, merge buckets for arcs that spawned the two nodes into the source arc*/ - for (arc = rg->arcs.first; arc; arc = arc->next) { - if (arc->head == srcArc->head && arc->tail == srcArc->tail && arc != srcArc) { - ReebNode *head = srcArc->head; - ReebNode *tail = srcArc->tail; - mergeArcBuckets(srcArc, arc, head->weight, tail->weight); - } - } - } - - /* second pass, replace removedNode by newNode, remove arcs that are collapsed in a loop */ - arc = rg->arcs.first; - while (arc) { - nextArc = arc->next; - - if (arc->head == removedNode || arc->tail == removedNode) { - if (arc->head == removedNode) { - arc->head = newNode; - } - else { - arc->tail = newNode; - } - - // Remove looped arcs - if (arc->head == arc->tail) { - // v1 or v2 was already newNode, since we're removing an arc, decrement degree - NodeDegreeDecrement(rg, newNode); - - // If it's srcArc, it'll be removed later, so keep it for now - if (arc != srcArc) { - BLI_remlink(&rg->arcs, arc); - REEB_freeArc((BArc *)arc); - } - } - else { - /* flip arcs that flipped, can happen on diamond shapes, mostly on null arcs */ - if (arc->head->weight > arc->tail->weight) { - flipArc(arc); - } - //newNode->degree++; // incrementing degree since we're adding an arc - NodeDegreeIncrement(rg, newNode); - mergeArcFaces(rg, arc, srcArc); - - if (merging) { - ReebNode *head = arc->head; - ReebNode *tail = arc->tail; - - // resize bucket list - resizeArcBuckets(arc); - mergeArcBuckets(arc, srcArc, head->weight, tail->weight); - - /* update length */ - arc->length += srcArc->length; - } - } - } - - arc = nextArc; - } -} - -void filterNullReebGraph(ReebGraph *rg) -{ - ReebArc *arc = NULL, *nextArc = NULL; - - arc = rg->arcs.first; - while (arc) { - nextArc = arc->next; - // Only collapse arcs too short to have any embed bucket - if (arc->bcount == 0) { - ReebNode *newNode = (ReebNode *)arc->head; - ReebNode *removedNode = (ReebNode *)arc->tail; - float blend; - - blend = (float)newNode->degree / (float)(newNode->degree + removedNode->degree); // blending factors - - interp_v3_v3v3(newNode->p, removedNode->p, newNode->p, blend); - - filterArc(rg, newNode, removedNode, arc, 0); - - // Reset nextArc, it might have changed - nextArc = arc->next; - - BLI_remlink(&rg->arcs, arc); - REEB_freeArc((BArc *)arc); - - BLI_removeNode((BGraph *)rg, (BNode *)removedNode); - } - - arc = nextArc; - } -} - -static int filterInternalExternalReebGraph(ReebGraph *rg, float threshold_internal, float threshold_external) -{ - ReebArc *arc = NULL, *nextArc = NULL; - int value = 0; - - BLI_listbase_sort(&rg->arcs, compareArcs); - - for (arc = rg->arcs.first; arc; arc = nextArc) { - nextArc = arc->next; - - /* Only collapse non-terminal arcs that are shorter than threshold */ - if ((threshold_internal > 0) && - (arc->head->degree > 1) && - (arc->tail->degree > 1) && - (lengthArc(arc) < threshold_internal)) - { - ReebNode *newNode = NULL; - ReebNode *removedNode = NULL; - - /* Always remove lower node, so arcs don't flip */ - newNode = arc->head; - removedNode = arc->tail; - - filterArc(rg, newNode, removedNode, arc, 1); - - // Reset nextArc, it might have changed - nextArc = arc->next; - - BLI_remlink(&rg->arcs, arc); - REEB_freeArc((BArc *)arc); - - BLI_removeNode((BGraph *)rg, (BNode *)removedNode); - value = 1; - } - - // Only collapse terminal arcs that are shorter than threshold - else if ((threshold_external > 0) && - (arc->head->degree == 1 || arc->tail->degree == 1) && - (lengthArc(arc) < threshold_external)) - { - ReebNode *terminalNode = NULL; - ReebNode *middleNode = NULL; - ReebNode *removedNode = NULL; - - // Assign terminal and middle nodes - if (arc->head->degree == 1) { - terminalNode = arc->head; - middleNode = arc->tail; - } - else { - terminalNode = arc->tail; - middleNode = arc->head; - } - - if (middleNode->degree == 2 && middleNode != rg->nodes.first) { -#if 1 - // If middle node is a normal node, it will be removed later - // Only if middle node is not the root node - /* USE THIS IF YOU WANT TO PROLONG ARCS TO THEIR TERMINAL NODES - * FOR HANDS, THIS IS NOT THE BEST RESULT - * */ - continue; -#else - removedNode = terminalNode; - - // removing arc, so we need to decrease the degree of the remaining node - NodeDegreeDecrement(rg, middleNode); -#endif - } - // Otherwise, just plain remove of the arc - else { - removedNode = terminalNode; - - // removing arc, so we need to decrease the degree of the remaining node - NodeDegreeDecrement(rg, middleNode); - } - - // Reset nextArc, it might have changed - nextArc = arc->next; - - BLI_remlink(&rg->arcs, arc); - REEB_freeArc((BArc *)arc); - - BLI_removeNode((BGraph *)rg, (BNode *)removedNode); - value = 1; - } - } - - return value; -} - -static int filterCyclesReebGraph(ReebGraph *rg, float UNUSED(distance_threshold)) -{ - ReebArc *arc1, *arc2; - ReebArc *next2; - int filtered = 0; - - for (arc1 = rg->arcs.first; arc1; arc1 = arc1->next) { - for (arc2 = arc1->next; arc2; arc2 = next2) { - next2 = arc2->next; - if (arc1 != arc2 && arc1->head == arc2->head && arc1->tail == arc2->tail) { - mergeArcEdges(rg, arc1, arc2, MERGE_APPEND); - mergeArcFaces(rg, arc1, arc2); - mergeArcBuckets(arc1, arc2, arc1->head->weight, arc1->tail->weight); - - NodeDegreeDecrement(rg, arc1->head); - NodeDegreeDecrement(rg, arc1->tail); - - BLI_remlink(&rg->arcs, arc2); - REEB_freeArc((BArc *)arc2); - - filtered = 1; - } - } - } - - return filtered; -} - -int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold)) -{ - int value = 0; -#if 0 //XXX - ReebArc *arc = NULL, *nextArc = NULL; - - BLI_listbase_sort(&rg->arcs, compareArcs); - -#ifdef DEBUG_REEB - { - EditFace *efa; - for (efa = G.editMesh->faces.first; efa; efa = efa->next) { - efa->tmp.fp = -1; - } - } -#endif - - arc = rg->arcs.first; - while (arc) - { - nextArc = arc->next; - - /* need correct normals and center */ - recalc_editnormals(); - - // Only test terminal arcs - if (arc->head->degree == 1 || arc->tail->degree == 1) - { - GHashIterator ghi; - int merging = 0; - int total = BLI_ghash_len(arc->faces); - float avg_angle = 0; - float avg_vec[3] = {0, 0, 0}; - - for (BLI_ghashIterator_init(&ghi, arc->faces); - BLI_ghashIterator_done(&ghi) == false; - BLI_ghashIterator_step(&ghi)) - { - EditFace *efa = BLI_ghashIterator_getValue(&ghi); - -#if 0 - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - EmbedBucket *bucket = NULL; - EmbedBucket *previous = NULL; - float min_distance = -1; - float angle = 0; - - initArcIterator(iter, arc, arc->head); - - bucket = nextBucket(iter); - - while (bucket != NULL) - { - float *vec0 = NULL; - float *vec1 = bucket->p; - float midpoint[3], tangent[3]; - float distance; - - /* first bucket. Previous is head */ - if (previous == NULL) - { - vec0 = arc->head->p; - } - /* Previous is a valid bucket */ - else { - vec0 = previous->p; - } - - copy_v3_v3(midpoint, vec1); - - distance = len_v3v3(midpoint, efa->cent); - - if (min_distance == -1 || distance < min_distance) - { - min_distance = distance; - - sub_v3_v3v3(tangent, vec1, vec0); - normalize_v3(tangent); - - angle = dot_v3v3(tangent, efa->n); - } - - previous = bucket; - bucket = nextBucket(iter); - } - - avg_angle += saacos(fabs(angle)); -#ifdef DEBUG_REEB - efa->tmp.fp = saacos(fabs(angle)); -#endif -#else - add_v3_v3(avg_vec, efa->n); -#endif - } - - -#if 0 - avg_angle /= total; -#else - mul_v3_fl(avg_vec, 1.0 / total); - avg_angle = dot_v3v3(avg_vec, avg_vec); -#endif - - arc->angle = avg_angle; - - if (avg_angle > threshold) - merging = 1; - - if (merging) { - ReebNode *terminalNode = NULL; - ReebNode *middleNode = NULL; - ReebNode *newNode = NULL; - ReebNode *removedNode = NULL; - int merging = 0; - - /* Assign terminal and middle nodes */ - if (arc->head->degree == 1) { - terminalNode = arc->head; - middleNode = arc->tail; - } - else { - terminalNode = arc->tail; - middleNode = arc->head; - } - - /* If middle node is a normal node, merge to terminal node */ - if (middleNode->degree == 2) { - merging = 1; - newNode = terminalNode; - removedNode = middleNode; - } - /* Otherwise, just plain remove of the arc */ - else { - merging = 0; - newNode = middleNode; - removedNode = terminalNode; - } - - /* Merging arc */ - if (merging) { - filterArc(rg, newNode, removedNode, arc, 1); - } - else { - /* removing arc, so we need to decrease the degree of the remaining node - *newNode->degree--; */ - NodeDegreeDecrement(rg, newNode); - } - - /* Reset nextArc, it might have changed */ - nextArc = arc->next; - - BLI_remlink(&rg->arcs, arc); - REEB_freeArc((BArc *)arc); - - BLI_freelinkN(&rg->nodes, removedNode); - value = 1; - } - } - - arc = nextArc; - } - -#endif - - return value; -} - -static void filterGraph(ReebGraph *rg, short options, float threshold_internal, float threshold_external) -{ - bool done = true; - - calculateGraphLength(rg); - - if ((options & SKGEN_FILTER_EXTERNAL) == 0) { - threshold_external = 0; - } - - if ((options & SKGEN_FILTER_INTERNAL) == 0) { - threshold_internal = 0; - } - - if (threshold_internal > 0 || threshold_external > 0) { - /* filter until there's nothing more to do */ - while (done == true) { - done = false; /* no work done yet */ - - done = filterInternalExternalReebGraph(rg, threshold_internal, threshold_external); - } - } - - if (options & SKGEN_FILTER_SMART) { - filterSmartReebGraph(rg, 0.5); - filterCyclesReebGraph(rg, 0.5); - } - - repositionNodes(rg); - - /* Filtering might have created degree 2 nodes, so remove them */ - removeNormalNodes(rg); -} - -static void finalizeGraph(ReebGraph *rg, char passes, char method) -{ - int i; - - BLI_buildAdjacencyList((BGraph *)rg); - - sortNodes(rg); - - sortArcs(rg); - - for (i = 0; i < passes; i++) { - postprocessGraph(rg, method); - } - - extendGraphBuckets(rg); -} - -/************************************** WEIGHT SPREADING ***********************************************/ - -static int compareVerts(const void *a, const void *b) -{ - EditVert *va = *(EditVert **)a; - EditVert *vb = *(EditVert **)b; - int value = 0; - - if (weightData(va) < weightData(vb)) { - value = -1; - } - else if (weightData(va) > weightData(vb)) { - value = 1; - } - - return value; -} - -static void spreadWeight(EditMesh *em) -{ - EditVert **verts, *eve; - float lastWeight = 0.0f; - int totvert = BLI_listbase_count(&em->verts); - int i; - int work_needed = 1; - - verts = MEM_callocN(sizeof(EditVert *) * totvert, "verts array"); - - for (eve = em->verts.first, i = 0; eve; eve = eve->next, i++) { - verts[i] = eve; - } - - while (work_needed == 1) { - work_needed = 0; - qsort(verts, totvert, sizeof(EditVert *), compareVerts); - - for (i = 0; i < totvert; i++) { - eve = verts[i]; - - if (i == 0 || (weightData(eve) - lastWeight) > FLT_EPSILON) { - lastWeight = weightData(eve); - } - else { - work_needed = 1; - weightSetData(eve, lastWeight + FLT_EPSILON * 2); - lastWeight = weightData(eve); - } - } - } - - MEM_freeN(verts); -} - -/******************************************** EXPORT ***************************************************/ - -static void exportNode(FILE *f, const char *text, ReebNode *node) -{ - fprintf(f, "%s i:%i w:%f d:%i %f %f %f\n", text, node->index, node->weight, node->degree, node->p[0], node->p[1], node->p[2]); -} - -void REEB_exportGraph(ReebGraph *rg, int count) -{ - ReebArc *arc; - char filename[128]; - FILE *f; - - if (count == -1) { - strcpy(filename, "test.txt"); - } - else { - sprintf(filename, "test%05i.txt", count); - } - f = BLI_fopen(filename, "w"); - - for (arc = rg->arcs.first; arc; arc = arc->next) { - int i; - float p[3]; - - exportNode(f, "v1", arc->head); - - for (i = 0; i < arc->bcount; i++) { - fprintf(f, "b nv:%i %f %f %f\n", arc->buckets[i].nv, arc->buckets[i].p[0], arc->buckets[i].p[1], arc->buckets[i].p[2]); - } - - add_v3_v3v3(p, arc->tail->p, arc->head->p); - mul_v3_fl(p, 0.5f); - - fprintf(f, "angle %0.3f %0.3f %0.3f %0.3f %i\n", p[0], p[1], p[2], arc->angle, BLI_ghash_len(arc->faces)); - exportNode(f, "v2", arc->tail); - } - - fclose(f); -} - -/***************************************** MAIN ALGORITHM **********************************************/ - -/* edges alone will create zero degree nodes, use this function to remove them */ -static void removeZeroNodes(ReebGraph *rg) -{ - ReebNode *node, *next_node; - - for (node = rg->nodes.first; node; node = next_node) { - next_node = node->next; - - if (node->degree == 0) { - BLI_removeNode((BGraph *)rg, (BNode *)node); - } - } -} - -void removeNormalNodes(ReebGraph *rg) -{ - ReebArc *arc, *nextArc; - - // Merge degree 2 nodes - for (arc = rg->arcs.first; arc; arc = nextArc) { - nextArc = arc->next; - - while (arc->head->degree == 2 || arc->tail->degree == 2) { - // merge at v1 - if (arc->head->degree == 2) { - ReebArc *connectedArc = (ReebArc *)BLI_findConnectedArc((BGraph *)rg, (BArc *)arc, (BNode *)arc->head); - - /* If arcs are one after the other */ - if (arc->head == connectedArc->tail) { - /* remove furthest arc */ - if (arc->tail->weight < connectedArc->head->weight) { - mergeConnectedArcs(rg, arc, connectedArc); - nextArc = arc->next; - } - else { - mergeConnectedArcs(rg, connectedArc, arc); - break; /* arc was removed, move to next */ - } - } - /* Otherwise, arcs are side by side */ - else { - /* Don't do anything, we need to keep the lowest node, even if degree 2 */ - break; - } - } - - /* merge at v2 */ - if (arc->tail->degree == 2) { - ReebArc *connectedArc = (ReebArc *)BLI_findConnectedArc((BGraph *)rg, (BArc *)arc, (BNode *)arc->tail); - - /* If arcs are one after the other */ - if (arc->tail == connectedArc->head) { - /* remove furthest arc */ - if (arc->head->weight < connectedArc->tail->weight) { - mergeConnectedArcs(rg, arc, connectedArc); - nextArc = arc->next; - } - else { - mergeConnectedArcs(rg, connectedArc, arc); - break; /* arc was removed, move to next */ - } - } - /* Otherwise, arcs are side by side */ - else { - /* Don't do anything, we need to keep the lowest node, even if degree 2 */ - break; - } - } - } - } - -} - -static int edgeEquals(ReebEdge *e1, ReebEdge *e2) -{ - return (e1->v1 == e2->v1 && e1->v2 == e2->v2); -} - -static ReebArc *nextArcMappedToEdge(ReebArc *arc, ReebEdge *e) -{ - ReebEdge *nextEdge = NULL; - ReebEdge *edge = NULL; - ReebArc *result = NULL; - - /* Find the ReebEdge in the edge list */ - for (edge = arc->edges.first; edge && !edgeEquals(edge, e); edge = edge->next) { } - - nextEdge = edge->nextEdge; - - if (nextEdge != NULL) { - result = nextEdge->arc; - } - - return result; -} - -void addFacetoArc(ReebArc *arc, EditFace *efa) -{ - BLI_ghash_insert(arc->faces, efa, efa); -} - -void mergeArcFaces(ReebGraph *UNUSED(rg), ReebArc *aDst, ReebArc *aSrc) -{ - GHashIterator ghi; - - for (BLI_ghashIterator_init(&ghi, aSrc->faces); - BLI_ghashIterator_done(&ghi) == false; - BLI_ghashIterator_step(&ghi)) - { - EditFace *efa = BLI_ghashIterator_getValue(&ghi); - BLI_ghash_insert(aDst->faces, efa, efa); - } -} - -void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction) -{ - ReebEdge *e = NULL; - - if (direction == MERGE_APPEND) { - for (e = aSrc->edges.first; e; e = e->next) { - e->arc = aDst; // Edge is stolen by new arc - } - - BLI_movelisttolist(&aDst->edges, &aSrc->edges); - } - else { - for (e = aSrc->edges.first; e; e = e->next) { - ReebEdge *newEdge = copyEdge(e); - - newEdge->arc = aDst; - - BLI_addtail(&aDst->edges, newEdge); - - if (direction == MERGE_LOWER) { - void **p = BLI_edgehash_lookup_p(rg->emap, e->v1->index, e->v2->index); - - newEdge->nextEdge = e; - - // if edge was the first in the list, point the edit edge to the new reeb edge instead. - if (*p == e) { - *p = (void *)newEdge; - } - // otherwise, advance in the list until the predecessor is found then insert it there - else { - ReebEdge *previous = (ReebEdge *)*p; - - while (previous->nextEdge != e) { - previous = previous->nextEdge; - } - - previous->nextEdge = newEdge; - } - } - else { - newEdge->nextEdge = e->nextEdge; - e->nextEdge = newEdge; - } - } - } -} - -// return 1 on full merge -int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1) -{ - int result = 0; - ReebNode *removedNode = NULL; - - a0->length += a1->length; - - mergeArcEdges(rg, a0, a1, MERGE_APPEND); - mergeArcFaces(rg, a0, a1); - - // Bring a0 to the combine length of both arcs - if (a0->tail == a1->head) { - removedNode = a0->tail; - a0->tail = a1->tail; - } - else if (a0->head == a1->tail) { - removedNode = a0->head; - a0->head = a1->head; - } - - resizeArcBuckets(a0); - // Merge a1 in a0 - mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); - - // remove a1 from graph - BLI_remlink(&rg->arcs, a1); - REEB_freeArc((BArc *)a1); - - BLI_removeNode((BGraph *)rg, (BNode *)removedNode); - result = 1; - - return result; -} -// return 1 on full merge -int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1) -{ - int result = 0; - /* TRIANGLE POINTS DOWN */ - if (a0->head->weight == a1->head->weight) { /* heads are the same */ - if (a0->tail->weight == a1->tail->weight) { /* tails also the same, arcs can be totally merge together */ - mergeArcEdges(rg, a0, a1, MERGE_APPEND); - mergeArcFaces(rg, a0, a1); - - mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); - - // Adjust node degree - //a1->head->degree--; - NodeDegreeDecrement(rg, a1->head); - //a1->tail->degree--; - NodeDegreeDecrement(rg, a1->tail); - - // remove a1 from graph - BLI_remlink(&rg->arcs, a1); - - REEB_freeArc((BArc *)a1); - result = 1; - } - else if (a0->tail->weight > a1->tail->weight) { /* a1->tail->weight is in the middle */ - mergeArcEdges(rg, a1, a0, MERGE_LOWER); - mergeArcFaces(rg, a1, a0); - - // Adjust node degree - //a0->head->degree--; - NodeDegreeDecrement(rg, a0->head); - //a1->tail->degree++; - NodeDegreeIncrement(rg, a1->tail); - - mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight); - a0->head = a1->tail; - resizeArcBuckets(a0); - } - else { /* a0>n2 is in the middle */ - mergeArcEdges(rg, a0, a1, MERGE_LOWER); - mergeArcFaces(rg, a0, a1); - - // Adjust node degree - //a1->head->degree--; - NodeDegreeDecrement(rg, a1->head); - //a0->tail->degree++; - NodeDegreeIncrement(rg, a0->tail); - - mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); - a1->head = a0->tail; - resizeArcBuckets(a1); - } - } - /* TRIANGLE POINTS UP */ - else if (a0->tail->weight == a1->tail->weight) { /* tails are the same */ - if (a0->head->weight > a1->head->weight) { /* a0->head->weight is in the middle */ - mergeArcEdges(rg, a0, a1, MERGE_HIGHER); - mergeArcFaces(rg, a0, a1); - - // Adjust node degree - //a1->tail->degree--; - NodeDegreeDecrement(rg, a1->tail); - //a0->head->degree++; - NodeDegreeIncrement(rg, a0->head); - - mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); - a1->tail = a0->head; - resizeArcBuckets(a1); - } - else { /* a1->head->weight is in the middle */ - mergeArcEdges(rg, a1, a0, MERGE_HIGHER); - mergeArcFaces(rg, a1, a0); - - // Adjust node degree - //a0->tail->degree--; - NodeDegreeDecrement(rg, a0->tail); - //a1->head->degree++; - NodeDegreeIncrement(rg, a1->head); - - mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight); - a0->tail = a1->head; - resizeArcBuckets(a0); - } - } - else { - /* Need something here (OR NOT) */ - } - - return result; -} - -static void glueByMergeSort(ReebGraph *rg, ReebArc *a0, ReebArc *a1, ReebEdge *e0, ReebEdge *e1) -{ - int total = 0; - while (total == 0 && a0 != a1 && a0 != NULL && a1 != NULL) { - total = mergeArcs(rg, a0, a1); - - if (total == 0) // if it wasn't a total merge, go forward { - if (a0->tail->weight < a1->tail->weight) { - a0 = nextArcMappedToEdge(a0, e0); - } - else { - a1 = nextArcMappedToEdge(a1, e1); - } - } - } -} - -static void mergePaths(ReebGraph *rg, ReebEdge *e0, ReebEdge *e1, ReebEdge *e2) -{ - ReebArc *a0, *a1, *a2; - a0 = e0->arc; - a1 = e1->arc; - a2 = e2->arc; - - glueByMergeSort(rg, a0, a1, e0, e1); - glueByMergeSort(rg, a0, a2, e0, e2); -} - -static ReebEdge *createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) -{ - ReebEdge *edge; - - edge = BLI_edgehash_lookup(rg->emap, node1->index, node2->index); - - // Only add existing edges that haven't been added yet - if (edge == NULL) { - ReebArc *arc; - ReebNode *v1, *v2; - float len, offset; - int i; - - arc = MEM_callocN(sizeof(ReebArc), "reeb arc"); - edge = MEM_callocN(sizeof(ReebEdge), "reeb edge"); - - arc->flag = 0; // clear flag on init - arc->symmetry_level = 0; - arc->faces = BLI_ghash_ptr_new("createArc gh"); - - if (node1->weight <= node2->weight) { - v1 = node1; - v2 = node2; - } - else { - v1 = node2; - v2 = node1; - } - - arc->head = v1; - arc->tail = v2; - - // increase node degree - //v1->degree++; - NodeDegreeIncrement(rg, v1); - //v2->degree++; - NodeDegreeIncrement(rg, v2); - - BLI_edgehash_insert(rg->emap, node1->index, node2->index, edge); - - edge->arc = arc; - edge->nextEdge = NULL; - edge->v1 = v1; - edge->v2 = v2; - - BLI_addtail(&rg->arcs, arc); - BLI_addtail(&arc->edges, edge); - - /* adding buckets for embedding */ - allocArcBuckets(arc); - - offset = arc->head->weight; - len = arc->tail->weight - arc->head->weight; - -#if 0 - /* This is the actual embedding filling described in the paper - * the problem is that it only works with really dense meshes - */ - if (arc->bcount > 0) - { - addVertToBucket(&(arc->buckets[0]), arc->head->co); - addVertToBucket(&(arc->buckets[arc->bcount - 1]), arc->tail->co); - } -#else - for (i = 0; i < arc->bcount; i++) { - float co[3]; - float f = (arc->buckets[i].val - offset) / len; - - interp_v3_v3v3(co, v1->p, v2->p, f); - addVertToBucket(&(arc->buckets[i]), co); - } -#endif - - } - - return edge; -} - -static void addTriangleToGraph(ReebGraph *rg, ReebNode *n1, ReebNode *n2, ReebNode *n3, EditFace *efa) -{ - ReebEdge *re1, *re2, *re3; - ReebEdge *e1, *e2, *e3; - float len1, len2, len3; - - re1 = createArc(rg, n1, n2); - re2 = createArc(rg, n2, n3); - re3 = createArc(rg, n3, n1); - - addFacetoArc(re1->arc, efa); - addFacetoArc(re2->arc, efa); - addFacetoArc(re3->arc, efa); - - len1 = (float)fabs(n1->weight - n2->weight); - len2 = (float)fabs(n2->weight - n3->weight); - len3 = (float)fabs(n3->weight - n1->weight); - - /* The rest of the algorithm assumes that e1 is the longest edge */ - - if (len1 >= len2 && len1 >= len3) { - e1 = re1; - e2 = re2; - e3 = re3; - } - else if (len2 >= len1 && len2 >= len3) { - e1 = re2; - e2 = re1; - e3 = re3; - } - else { - e1 = re3; - e2 = re2; - e3 = re1; - } - - /* And e2 is the lowest edge - * If e3 is lower than e2, swap them - */ - if (e3->v1->weight < e2->v1->weight) { - ReebEdge *etmp = e2; - e2 = e3; - e3 = etmp; - } - - - mergePaths(rg, e1, e2, e3); -} - -ReebGraph *generateReebGraph(EditMesh *em, int subdivisions) -{ - ReebGraph *rg; - EditVert *eve; - EditFace *efa; - int index; - /*int totvert;*/ - -#ifdef DEBUG_REEB - int totfaces; - int countfaces = 0; -#endif - - rg = newReebGraph(); - - rg->resolution = subdivisions; - - /*totvert = BLI_listbase_count(&em->verts);*/ /*UNUSED*/ -#ifdef DEBUG_REEB - totfaces = BLI_listbase_count(&em->faces); -#endif - - renormalizeWeight(em, 1.0f); - - /* Spread weight to minimize errors */ - spreadWeight(em); - - renormalizeWeight(em, (float)rg->resolution); - - /* Adding vertice */ - for (index = 0, eve = em->verts.first; eve; eve = eve->next) { - if (eve->h == 0) { - addNode(rg, eve); - eve->f2 = 0; - index++; - } - } - - /* Adding face, edge per edge */ - for (efa = em->faces.first; efa; efa = efa->next) { - if (efa->h == 0) { - ReebNode *n1, *n2, *n3; - - n1 = nodeData(efa->v1); - n2 = nodeData(efa->v2); - n3 = nodeData(efa->v3); - - addTriangleToGraph(rg, n1, n2, n3, efa); - - if (efa->v4) { - ReebNode *n4 = nodeData(efa->v4); - addTriangleToGraph(rg, n1, n3, n4, efa); - } -#ifdef DEBUG_REEB - countfaces++; - if (countfaces % 100 == 0) { - printf("\rface %i of %i", countfaces, totfaces); - } -#endif - } - } - - printf("\n"); - - removeZeroNodes(rg); - - removeNormalNodes(rg); - - return rg; -} - -/***************************************** WEIGHT UTILS **********************************************/ - -void renormalizeWeight(EditMesh *em, float newmax) -{ - EditVert *eve; - float minimum, maximum, range; - - if (em == NULL || BLI_listbase_is_empty(&em->verts)) - return; - - /* First pass, determine maximum and minimum */ - eve = em->verts.first; - minimum = weightData(eve); - maximum = minimum; - for (; eve; eve = eve->next) { - maximum = MAX2(maximum, weightData(eve)); - minimum = MIN2(minimum, weightData(eve)); - } - - range = maximum - minimum; - - /* Normalize weights */ - for (eve = em->verts.first; eve; eve = eve->next) { - float weight = (weightData(eve) - minimum) / range * newmax; - weightSetData(eve, weight); - } -} - - -int weightFromLoc(EditMesh *em, int axis) -{ - EditVert *eve; - - if (em == NULL || BLI_listbase_is_empty(&em->verts) || axis < 0 || axis > 2) - return 0; - - /* Copy coordinate in weight */ - for (eve = em->verts.first; eve; eve = eve->next) { - weightSetData(eve, eve->co[axis]); - } - - return 1; -} - -static void addTriangle(LinearSolver *context, EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2, int e3) -{ - /* Angle opposite e1 */ - float t1 = cotangent_tri_weight_v3(v1->co, v2->co, v3->co) / e2; - - /* Angle opposite e2 */ - float t2 = cotangent_tri_weight_v3(v2->co, v3->co, v1->co) / e3; - - /* Angle opposite e3 */ - float t3 = cotangent_tri_weight_v3(v3->co, v1->co, v2->co) / e1; - - int i1 = indexData(v1); - int i2 = indexData(v2); - int i3 = indexData(v3); - - EIG_linear_solver_matrix_add(context, i1, i1, t2 + t3); - EIG_linear_solver_matrix_add(context, i2, i2, t1 + t3); - EIG_linear_solver_matrix_add(context, i3, i3, t1 + t2); - - EIG_linear_solver_matrix_add(context, i1, i2, -t3); - EIG_linear_solver_matrix_add(context, i2, i1, -t3); - - EIG_linear_solver_matrix_add(context, i2, i3, -t1); - EIG_linear_solver_matrix_add(context, i3, i2, -t1); - - EIG_linear_solver_matrix_add(context, i3, i1, -t2); - EIG_linear_solver_matrix_add(context, i1, i3, -t2); -} - -int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) -{ - LinearSolver *context; - NLboolean success; - EditVert *eve; - EditEdge *eed; - EditFace *efa; - int totvert = 0; - int index; - int rval; - - /* Find local extrema */ - for (eve = em->verts.first; eve; eve = eve->next) { - totvert++; - } - - /* Solve */ - - context = EIG_linear_solver_new(, 0, totvert, 1); - - /* Find local extrema */ - for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) { - if (eve->h == 0) { - EditEdge *eed; - int maximum = 1; - int minimum = 1; - - NextEdgeForVert(indexed_edges, -1); /* Reset next edge */ - for (eed = NextEdgeForVert(indexed_edges, index); eed && (maximum || minimum); eed = NextEdgeForVert(indexed_edges, index)) { - EditVert *eve2; - - if (eed->v1 == eve) { - eve2 = eed->v2; - } - else { - eve2 = eed->v1; - } - - if (eve2->h == 0) { - /* Adjacent vertex is bigger, not a local maximum */ - if (weightData(eve2) > weightData(eve)) { - maximum = 0; - } - /* Adjacent vertex is smaller, not a local minimum */ - else if (weightData(eve2) < weightData(eve)) { - minimum = 0; - } - } - } - - if (maximum || minimum) { - float w = weightData(eve); - eve->f1 = 0; - EIG_linear_solver_variable_set(context, 0, index, w); - EIG_linear_solver_variable_lock(context, index); - } - else { - eve->f1 = 1; - } - } - } - - /* Zero edge weight */ - for (eed = em->edges.first; eed; eed = eed->next) { - eed->tmp.l = 0; - } - - /* Add faces count to the edge weight */ - for (efa = em->faces.first; efa; efa = efa->next) { - if (efa->h == 0) { - efa->e1->tmp.l++; - efa->e2->tmp.l++; - efa->e3->tmp.l++; - - if (efa->e4) { - efa->e4->tmp.l++; - } - } - } - - /* Add faces angle to the edge weight */ - for (efa = em->faces.first; efa; efa = efa->next) { - if (efa->h == 0) { - if (efa->v4 == NULL) { - addTriangle(context, efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, efa->e3->tmp.l); - } - else { - addTriangle(context, efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, 2); - addTriangle(context, efa->v3, efa->v4, efa->v1, efa->e3->tmp.l, efa->e4->tmp.l, 2); - } - } - } - - success = EIG_linear_solver_solve(context); - - if (success) { - rval = 1; - for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) { - weightSetData(eve, EIG_linear_solver_variable_get(context, 0, index)); - } - } - else { - rval = 0; - } - - EIG_linear_solver_delete(context); - - return rval; -} - - -EditEdge *NextEdgeForVert(EdgeIndex *indexed_edges, int index) -{ - static int offset = -1; - - /* Reset method, call with NULL mesh pointer */ - if (index == -1) { - offset = -1; - return NULL; - } - - /* first pass, start at the head of the list */ - if (offset == -1) { - offset = indexed_edges->offset[index]; - } - /* subsequent passes, start on the next edge */ - else { - offset++; - } - - return indexed_edges->edges[offset]; -} - -static void shortestPathsFromVert(EditMesh *em, EditVert *starting_vert, EdgeIndex *indexed_edges) -{ - Heap *edge_heap; - EditVert *current_eve = NULL; - EditEdge *eed = NULL; - EditEdge *select_eed = NULL; - - edge_heap = BLI_heap_new(); - - current_eve = starting_vert; - - /* insert guard in heap, when that is returned, no more edges */ - BLI_heap_insert(edge_heap, FLT_MAX, NULL); - - /* Initialize edge flag */ - for (eed = em->edges.first; eed; eed = eed->next) { - eed->f1 = 0; - } - - while (BLI_heap_len(edge_heap) > 0) { - float current_weight; - - current_eve->f1 = 1; /* mark vertex as selected */ - - /* Add all new edges connected to current_eve to the list */ - NextEdgeForVert(indexed_edges, -1); // Reset next edge - for (eed = NextEdgeForVert(indexed_edges, indexData(current_eve)); eed; eed = NextEdgeForVert(indexed_edges, indexData(current_eve))) { - if (eed->f1 == 0) { - BLI_heap_insert(edge_heap, weightData(current_eve) + eed->tmp.fp, eed); - eed->f1 = 1; - } - } - - /* Find next shortest edge with unselected verts */ - do { - current_weight = BLI_heap_node_value(BLI_heap_top(edge_heap)); - select_eed = BLI_heap_pop_min(edge_heap); - } while (select_eed != NULL && select_eed->v1->f1 != 0 && select_eed->v2->f1); - - if (select_eed != NULL) { - select_eed->f1 = 2; - - if (select_eed->v1->f1 == 0) /* v1 is the new vertex */ { - current_eve = select_eed->v1; - } - else { /* otherwise, it's v2 */ - current_eve = select_eed->v2; - } - - weightSetData(current_eve, current_weight); - } - } - - BLI_heap_free(edge_heap, NULL); -} - -static void freeEdgeIndex(EdgeIndex *indexed_edges) -{ - MEM_freeN(indexed_edges->offset); - MEM_freeN(indexed_edges->edges); -} - -static void buildIndexedEdges(EditMesh *em, EdgeIndex *indexed_edges) -{ - EditVert *eve; - EditEdge *eed; - int totvert = 0; - int tot_indexed = 0; - int offset = 0; - - totvert = BLI_listbase_count(&em->verts); - - indexed_edges->offset = MEM_callocN(totvert * sizeof(int), "EdgeIndex offset"); - - for (eed = em->edges.first; eed; eed = eed->next) { - if (eed->v1->h == 0 && eed->v2->h == 0) { - tot_indexed += 2; - indexed_edges->offset[indexData(eed->v1)]++; - indexed_edges->offset[indexData(eed->v2)]++; - } - } - - tot_indexed += totvert; - - indexed_edges->edges = MEM_callocN(tot_indexed * sizeof(EditEdge *), "EdgeIndex edges"); - - /* setting vert offsets */ - for (eve = em->verts.first; eve; eve = eve->next) { - if (eve->h == 0) { - int d = indexed_edges->offset[indexData(eve)]; - indexed_edges->offset[indexData(eve)] = offset; - offset += d + 1; - } - } - - /* adding edges in array */ - for (eed = em->edges.first; eed; eed = eed->next) { - if (eed->v1->h == 0 && eed->v2->h == 0) { - int i; - for (i = indexed_edges->offset[indexData(eed->v1)]; i < tot_indexed; i++) { - if (indexed_edges->edges[i] == NULL) { - indexed_edges->edges[i] = eed; - break; - } - } - - for (i = indexed_edges->offset[indexData(eed->v2)]; i < tot_indexed; i++) { - if (indexed_edges->edges[i] == NULL) { - indexed_edges->edges[i] = eed; - break; - } - } - } - } -} - -int weightFromDistance(EditMesh *em, EdgeIndex *indexed_edges) -{ - EditVert *eve; - int totedge = 0; - int totvert = 0; - int vCount = 0; - - totvert = BLI_listbase_count(&em->verts); - - if (em == NULL || totvert == 0) { - return 0; - } - - totedge = BLI_listbase_count(&em->edges); - - if (totedge == 0) { - return 0; - } - - /* Initialize vertice flag and find at least one selected vertex */ - for (eve = em->verts.first; eve; eve = eve->next) { - eve->f1 = 0; - if (eve->f & SELECT) { - vCount = 1; - } - } - - if (vCount == 0) { - return 0; /* no selected vert, failure */ - } - else { - EditEdge *eed; - int allDone = 0; - - /* Calculate edge weight */ - for (eed = em->edges.first; eed; eed = eed->next) { - if (eed->v1->h == 0 && eed->v2->h == 0) { - eed->tmp.fp = len_v3v3(eed->v1->co, eed->v2->co); - } - } - - /* Apply dijkstra spf for each selected vert */ - for (eve = em->verts.first; eve; eve = eve->next) { - if (eve->f & SELECT) { - shortestPathsFromVert(em, eve, indexed_edges); - } - } - - /* connect unselected islands */ - while (allDone == 0) { - EditVert *selected_eve = NULL; - float selected_weight = 0; - float min_distance = FLT_MAX; - - allDone = 1; - - for (eve = em->verts.first; eve; eve = eve->next) { - /* for every vertex visible that hasn't been processed yet */ - if (eve->h == 0 && eve->f1 != 1) { - EditVert *closest_eve; - - /* find the closest processed vertex */ - for (closest_eve = em->verts.first; closest_eve; closest_eve = closest_eve->next) { - /* vertex is already processed and distance is smaller than current minimum */ - if (closest_eve->f1 == 1) { - float distance = len_v3v3(closest_eve->co, eve->co); - if (distance < min_distance) { - min_distance = distance; - selected_eve = eve; - selected_weight = weightData(closest_eve); - } - } - } - } - } - - if (selected_eve) { - allDone = 0; - - weightSetData(selected_eve, selected_weight + min_distance); - shortestPathsFromVert(em, selected_eve, indexed_edges); - } - } - } - - for (eve = em->verts.first; eve && vCount == 0; eve = eve->next) { - if (eve->f1 == 0) { - printf("vertex not reached\n"); - break; - } - } - - return 1; -} -#endif - -/****************************************** BUCKET ITERATOR **************************************************/ - -static void *headNode(void *arg); -static void *tailNode(void *arg); -static void *nextBucket(void *arg); -static void *nextNBucket(void *arg, int n); -static void *peekBucket(void *arg, int n); -static void *previousBucket(void *arg); -static int iteratorStopped(void *arg); - -static void initIteratorFct(ReebArcIterator *iter) -{ - iter->head = headNode; - iter->tail = tailNode; - iter->peek = peekBucket; - iter->next = nextBucket; - iter->nextN = nextNBucket; - iter->previous = previousBucket; - iter->stopped = iteratorStopped; -} - -static void setIteratorValues(ReebArcIterator *iter, EmbedBucket *bucket) -{ - if (bucket) { - iter->p = bucket->p; - iter->no = bucket->no; - } - else { - iter->p = NULL; - iter->no = NULL; - } - iter->size = 0; -} - -void initArcIterator(BArcIterator *arg, ReebArc *arc, ReebNode *head) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - - initIteratorFct(iter); - iter->arc = arc; - - if (head == arc->head) { - iter->start = 0; - iter->end = arc->bcount - 1; - iter->stride = 1; - } - else { - iter->start = arc->bcount - 1; - iter->end = 0; - iter->stride = -1; - } - - iter->length = arc->bcount; - - iter->index = -1; -} - -void initArcIteratorStart(BArcIterator *arg, struct ReebArc *arc, struct ReebNode *head, int start) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - - initIteratorFct(iter); - iter->arc = arc; - - if (head == arc->head) { - iter->start = start; - iter->end = arc->bcount - 1; - iter->stride = 1; - } - else { - iter->start = arc->bcount - 1 - start; - iter->end = 0; - iter->stride = -1; - } - - iter->index = -1; - - iter->length = arc->bcount - start; - - if (start >= arc->bcount) { - iter->start = iter->end; /* stop iterator since it's past its end */ - } -} - -void initArcIterator2(BArcIterator *arg, ReebArc *arc, int start, int end) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - - initIteratorFct(iter); - iter->arc = arc; - - iter->start = start; - iter->end = end; - - if (end > start) { - iter->stride = 1; - } - else { - iter->stride = -1; - } - - iter->index = -1; - - iter->length = abs(iter->end - iter->start) + 1; -} - -static void *headNode(void *arg) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - ReebNode *node; - - if (iter->start < iter->end) { - node = iter->arc->head; - } - else { - node = iter->arc->tail; - } - - iter->p = node->p; - iter->no = node->no; - iter->size = 0; - - return node; -} - -static void *tailNode(void *arg) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - ReebNode *node; - - if (iter->start < iter->end) { - node = iter->arc->tail; - } - else { - node = iter->arc->head; - } - - iter->p = node->p; - iter->no = node->no; - iter->size = 0; - - return node; -} - -static void *nextBucket(void *arg) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - EmbedBucket *result = NULL; - - iter->index++; - - if (iter->index < iter->length) { - result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]); - } - - setIteratorValues(iter, result); - return result; -} - -static void *nextNBucket(void *arg, int n) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - EmbedBucket *result = NULL; - - iter->index += n; - - /* check if passed end */ - if (iter->index < iter->length) { - result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]); - } - - setIteratorValues(iter, result); - return result; -} - -static void *peekBucket(void *arg, int n) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - EmbedBucket *result = NULL; - int index = iter->index + n; - - /* check if passed end */ - if (index < iter->length) { - result = &(iter->arc->buckets[iter->start + (iter->stride * index)]); - } - - setIteratorValues(iter, result); - return result; -} - -static void *previousBucket(void *arg) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - EmbedBucket *result = NULL; - - if (iter->index > 0) { - iter->index--; - result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]); - } - - setIteratorValues(iter, result); - return result; -} - -static int iteratorStopped(void *arg) -{ - ReebArcIterator *iter = (ReebArcIterator *)arg; - - if (iter->index >= iter->length) { - return 1; - } - else { - return 0; - } -} - -/************************ PUBLIC FUNCTIONS *********************************************/ - -ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C) -{ - (void)C; - return NULL; -#if 0 - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - EditMesh *em = BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - EdgeIndex indexed_edges; - VertexData *data; - ReebGraph *rg = NULL; - ReebGraph *rgi, *previous; - int i, nb_levels = REEB_MAX_MULTI_LEVEL; - - if (em == NULL) - return NULL; - - data = allocVertexData(em); - - buildIndexedEdges(em, &indexed_edges); - - if (weightFromDistance(em, &indexed_edges) == 0) - { - // XXX error("No selected vertex\n"); - freeEdgeIndex(&indexed_edges); - return NULL; - } - - renormalizeWeight(em, 1.0f); - - if (scene->toolsettings->skgen_options & SKGEN_HARMONIC) - { - weightToHarmonic(em, &indexed_edges); - } - - freeEdgeIndex(&indexed_edges); - - rg = generateReebGraph(em, scene->toolsettings->skgen_resolution); - - /* Remove arcs without embedding */ - filterNullReebGraph(rg); - - /* smart filter and loop filter on basic level */ - filterGraph(rg, SKGEN_FILTER_SMART, 0, 0); - - repositionNodes(rg); - - /* Filtering might have created degree 2 nodes, so remove them */ - removeNormalNodes(rg); - - joinSubgraphs(rg, 1.0); - - BLI_buildAdjacencyList((BGraph *)rg); - - /* calc length before copy, so we have same length on all levels */ - BLI_calcGraphLength((BGraph *)rg); - - previous = NULL; - for (i = 0; i <= nb_levels; i++) - { - rgi = rg; - - /* don't filter last level */ - if (i > 0) - { - float internal_threshold; - float external_threshold; - - /* filter internal progressively in second half only*/ - if (i > nb_levels / 2) - { - internal_threshold = rg->length * scene->toolsettings->skgen_threshold_internal; - } - else { - internal_threshold = rg->length * scene->toolsettings->skgen_threshold_internal * (2 * i / (float)nb_levels); - } - - external_threshold = rg->length * scene->toolsettings->skgen_threshold_external * (i / (float)nb_levels); - - filterGraph(rgi, scene->toolsettings->skgen_options, internal_threshold, external_threshold); - } - - if (i < nb_levels) - { - rg = copyReebGraph(rgi, i + 1); - } - - finalizeGraph(rgi, scene->toolsettings->skgen_postpro_passes, scene->toolsettings->skgen_postpro); - - BLI_markdownSymmetry((BGraph *)rgi, rgi->nodes.first, scene->toolsettings->skgen_symmetry_limit); - - if (previous != NULL) - { - relinkNodes(rgi, previous); - } - previous = rgi; - } - - verifyMultiResolutionLinks(rg, 0); - - MEM_freeN(data); - - /* no need to load the editmesh back into the object, just - * free it (avoids ngon conversion issues too going back the other way) */ - free_editMesh(em); - MEM_freeN(em); - - return rg; -#endif -} - -#if 0 - -ReebGraph *BIF_ReebGraphFromEditMesh(void) -{ - EditMesh *em = G.editMesh; - EdgeIndex indexed_edges; - VertexData *data; - ReebGraph *rg = NULL; - - if (em == NULL) - return NULL; - - data = allocVertexData(em); - - buildIndexedEdges(em, &indexed_edges); - - if (weightFromDistance(em, &indexed_edges) == 0) - { - error("No selected vertex\n"); - freeEdgeIndex(&indexed_edges); - freeEdgeIndex(&indexed_edges); - return NULL; - } - - renormalizeWeight(em, 1.0f); - - if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC) - { - weightToHarmonic(em, &indexed_edges); - } - - freeEdgeIndex(&indexed_edges); - -#ifdef DEBUG_REEB -// weightToVCol(em, 1); -#endif - - rg = generateReebGraph(em, G.scene->toolsettings->skgen_resolution); - - - /* Remove arcs without embedding */ - filterNullReebGraph(rg); - - /* smart filter and loop filter on basic level */ - filterGraph(rg, SKGEN_FILTER_SMART, 0, 0); - - repositionNodes(rg); - - /* Filtering might have created degree 2 nodes, so remove them */ - removeNormalNodes(rg); - - joinSubgraphs(rg, 1.0); - - BLI_buildAdjacencyList((BGraph *)rg); - - /* calc length before copy, so we have same length on all levels */ - BLI_calcGraphLength((BGraph *)rg); - - filterGraph(rg, G.scene->toolsettings->skgen_options, G.scene->toolsettings->skgen_threshold_internal, G.scene->toolsettings->skgen_threshold_external); - - finalizeGraph(rg, G.scene->toolsettings->skgen_postpro_passes, G.scene->toolsettings->skgen_postpro); - -#ifdef DEBUG_REEB - REEB_exportGraph(rg, -1); - - arcToVCol(rg, em, 0); - //angleToVCol(em, 1); -#endif - - printf("DONE\n"); - printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph *)rg)); - - MEM_freeN(data); - - return rg; -} - -void BIF_GlobalReebFree() -{ - if (GLOBAL_RG != NULL) - { - REEB_freeGraph(GLOBAL_RG); - GLOBAL_RG = NULL; - } -} - -void BIF_GlobalReebGraphFromEditMesh(void) -{ - ReebGraph *rg; - - BIF_GlobalReebFree(); - - rg = BIF_ReebGraphMultiFromEditMesh(); - - GLOBAL_RG = rg; -} - -void REEB_draw() -{ - ReebGraph *rg; - ReebArc *arc; - int i = 0; - - if (GLOBAL_RG == NULL) - { - return; - } - - if (GLOBAL_RG->link_up && G.scene->toolsettings->skgen_options & SKGEN_DISP_ORIG) - { - for (rg = GLOBAL_RG; rg->link_up; rg = rg->link_up) ; - } - else { - i = G.scene->toolsettings->skgen_multi_level; - - for (rg = GLOBAL_RG; rg->multi_level != i && rg->link_up; rg = rg->link_up) ; - } - - glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE)); - - glDisable(GL_DEPTH_TEST); - for (arc = rg->arcs.first; arc; arc = arc->next, i++) - { - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - float vec[3]; - char text[128]; - char *s = text; - - glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE) + 2); - glColor3f(0, 0, 0); - glBegin(GL_LINE_STRIP); - glVertex3fv(arc->head->p); - - if (arc->bcount) - { - initArcIterator(iter, arc, arc->head); - for (IT_next(iter); IT_stopped(iter) == 0; IT_next(iter)) - { - glVertex3fv(iter->p); - } - } - - glVertex3fv(arc->tail->p); - glEnd(); - - glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE)); - - if (arc->symmetry_level == 1) - { - glColor3f(1, 0, 0); - } - else if (arc->symmetry_flag == SYM_SIDE_POSITIVE || arc->symmetry_flag == SYM_SIDE_NEGATIVE) - { - glColor3f(1, 0.5f, 0); - } - else if (arc->symmetry_flag >= SYM_SIDE_RADIAL) - { - glColor3f(0.5f, 1, 0); - } - else { - glColor3f(1, 1, 0); - } - glBegin(GL_LINE_STRIP); - glVertex3fv(arc->head->p); - - if (arc->bcount) - { - initArcIterator(iter, arc, arc->head); - for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter)) - { - glVertex3fv(iter->p); - } - } - - glVertex3fv(arc->tail->p); - glEnd(); - - - if (G.scene->toolsettings->skgen_options & SKGEN_DISP_EMBED) - { - glColor3f(1, 1, 1); - glBegin(GL_POINTS); - glVertex3fv(arc->head->p); - glVertex3fv(arc->tail->p); - - glColor3f(0.5f, 0.5f, 1); - if (arc->bcount) - { - initArcIterator(iter, arc, arc->head); - for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter)) - { - glVertex3fv(iter->p); - } - } - glEnd(); - } - - if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX) - { - mid_v3_v3v3(vec, arc->head->p, arc->tail->p); - s += sprintf(s, "%i (%i-%i-%i) ", i, arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); - - if (G.scene->toolsettings->skgen_options & SKGEN_DISP_WEIGHT) - { - s += sprintf(s, "w:%0.3f ", arc->tail->weight - arc->head->weight); - } - - if (G.scene->toolsettings->skgen_options & SKGEN_DISP_LENGTH) - { - s += sprintf(s, "l:%0.3f", arc->length); - } - - glColor3f(0, 1, 0); - glRasterPos3fv(vec); - BMF_DrawString(G.fonts, text); - } - - if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX) - { - sprintf(text, " %i", arc->head->index); - glRasterPos3fv(arc->head->p); - BMF_DrawString(G.fonts, text); - - sprintf(text, " %i", arc->tail->index); - glRasterPos3fv(arc->tail->p); - BMF_DrawString(G.fonts, text); - } - } - glEnable(GL_DEPTH_TEST); -} - -#endif diff --git a/source/blender/editors/armature/reeb.h b/source/blender/editors/armature/reeb.h deleted file mode 100644 index 9eed343f18a..00000000000 --- a/source/blender/editors/armature/reeb.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * ***** 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): Martin Poirier - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/armature/reeb.h - * \ingroup edarmature - */ - - -#ifndef __REEB_H__ -#define __REEB_H__ - -#define WITH_BF_REEB - -#include "DNA_listBase.h" - -#include "BLI_graph.h" - -struct GHash; -struct EdgeHash; -struct ReebArc; -struct ReebEdge; -struct ReebNode; - -typedef struct ReebGraph { - ListBase arcs; - ListBase nodes; - - float length; - - FreeArc free_arc; - FreeNode free_node; - RadialSymmetry radial_symmetry; - AxialSymmetry axial_symmetry; - /*********************************/ - - int resolution; - int totnodes; - struct EdgeHash *emap; - int multi_level; - struct ReebGraph *link_up; /* for multi resolution filtering, points to higher levels */ -} ReebGraph; - -typedef struct EmbedBucket { - float val; - int nv; - float p[3]; - float no[3]; /* if non-null, normal of the bucket */ -} EmbedBucket; - -typedef struct ReebNode { - void *next, *prev; - float p[3]; - int flag; - - int degree; - struct ReebArc **arcs; - - int subgraph_index; - - int symmetry_level; - int symmetry_flag; - float symmetry_axis[3]; - /*********************************/ - - float no[3]; - - int index; - float weight; - int multi_level; - struct ReebNode *link_down; /* for multi resolution filtering, points to lower levels, if present */ - struct ReebNode *link_up; -} ReebNode; - -typedef struct ReebEdge { - struct ReebEdge *next, *prev; - struct ReebArc *arc; - struct ReebNode *v1, *v2; - struct ReebEdge *nextEdge; - int flag; -} ReebEdge; - -typedef struct ReebArc { - void *next, *prev; - struct ReebNode *head, *tail; - int flag; - - float length; - - int symmetry_level; - int symmetry_group; - int symmetry_flag; - /*********************************/ - - ListBase edges; - int bcount; - struct EmbedBucket *buckets; - - struct GHash *faces; - float angle; - struct ReebArc *link_up; /* for multi resolution filtering, points to higher levels */ -} ReebArc; - -typedef struct ReebArcIterator { - HeadFct head; - TailFct tail; - PeekFct peek; - NextFct next; - NextNFct nextN; - PreviousFct previous; - StoppedFct stopped; - - float *p, *no; - float size; - - int length; - int index; - /*********************************/ - struct ReebArc *arc; - int start; - int end; - int stride; -} ReebArcIterator; - -#if 0 -struct EditMesh; -struct EdgeIndex; - -int weightToHarmonic(struct EditMesh *em, struct EdgeIndex *indexed_edges); -int weightFromDistance(struct EditMesh *em, struct EdgeIndex *indexed_edges); -int weightFromLoc(struct EditMesh *me, int axis); -//void weightToVCol(struct EditMesh *em, int index); -void arcToVCol(struct ReebGraph *rg, struct EditMesh *em, int index); -//void angleToVCol(struct EditMesh *em, int index); -void renormalizeWeight(struct EditMesh *em, float newmax); - -ReebGraph *generateReebGraph(struct EditMesh *me, int subdivisions); -#endif - -ReebGraph *newReebGraph(void); - -void initArcIterator(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head); -void initArcIterator2(BArcIterator *iter, struct ReebArc *arc, int start, int end); -void initArcIteratorStart(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start); - -/* Filtering */ -void filterNullReebGraph(ReebGraph *rg); -int filterSmartReebGraph(ReebGraph *rg, float threshold); - -/* Post-Build processing */ -void repositionNodes(ReebGraph *rg); -void postprocessGraph(ReebGraph *rg, char mode); -void removeNormalNodes(ReebGraph *rg); - -void sortNodes(ReebGraph *rg); -void sortArcs(ReebGraph *rg); - -/*------------ Sanity check ------------*/ -void verifyBuckets(ReebGraph *rg); -void verifyFaces(ReebGraph *rg); -void verifyArcs(ReebGraph *rg); -void verifyNodeDegree(ReebGraph *rg); - -/*********************** PUBLIC *********************************/ - -#define REEB_MAX_MULTI_LEVEL 10 - -struct bContext; - -ReebGraph *BIF_ReebGraphFromEditMesh(void); -ReebGraph *BIF_ReebGraphMultiFromEditMesh(struct bContext *C); -void BIF_flagMultiArcs(ReebGraph *rg, int flag); - -void BIF_GlobalReebGraphFromEditMesh(void); -void BIF_GlobalReebFree(void); - -ReebNode *BIF_otherNodeFromIndex(ReebArc *arc, ReebNode *node); -ReebNode *BIF_NodeFromIndex(ReebArc *arc, ReebNode *node); -ReebNode *BIF_lowestLevelNode(ReebNode *node); - -ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node); - -void REEB_freeGraph(ReebGraph *rg); -void REEB_freeArc(BArc *barc); -void REEB_exportGraph(ReebGraph *rg, int count); -void REEB_draw(void); - - -#endif /*__REEB_H__*/ |