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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/armature')
-rw-r--r--source/blender/editors/armature/BIF_generate.h49
-rw-r--r--source/blender/editors/armature/BIF_retarget.h171
-rw-r--r--source/blender/editors/armature/CMakeLists.txt9
-rw-r--r--source/blender/editors/armature/armature_add.c24
-rw-r--r--source/blender/editors/armature/armature_edit.c119
-rw-r--r--source/blender/editors/armature/armature_intern.h24
-rw-r--r--source/blender/editors/armature/armature_naming.c7
-rw-r--r--source/blender/editors/armature/armature_ops.c50
-rw-r--r--source/blender/editors/armature/armature_relations.c35
-rw-r--r--source/blender/editors/armature/armature_select.c352
-rw-r--r--source/blender/editors/armature/armature_skinning.c72
-rw-r--r--source/blender/editors/armature/armature_utils.c9
-rw-r--r--source/blender/editors/armature/editarmature_generate.c305
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c2663
-rw-r--r--source/blender/editors/armature/editarmature_undo.c84
-rw-r--r--source/blender/editors/armature/meshlaplacian.c55
-rw-r--r--source/blender/editors/armature/meshlaplacian.h9
-rw-r--r--source/blender/editors/armature/pose_edit.c224
-rw-r--r--source/blender/editors/armature/pose_group.c25
-rw-r--r--source/blender/editors/armature/pose_lib.c38
-rw-r--r--source/blender/editors/armature/pose_select.c307
-rw-r--r--source/blender/editors/armature/pose_slide.c6
-rw-r--r--source/blender/editors/armature/pose_transform.c280
-rw-r--r--source/blender/editors/armature/pose_utils.c14
-rw-r--r--source/blender/editors/armature/reeb.c3435
-rw-r--r--source/blender/editors/armature/reeb.h207
26 files changed, 1084 insertions, 7489 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 0f382f07671..ccc1eefd9dc 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -48,9 +48,11 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_object.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -139,17 +141,16 @@ void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const b
/* exported for use in editors/object/ */
/* 0 == do center, 1 == center new, 2 == center cursor */
-void ED_armature_origin_set(Main *bmain, Scene *scene, Object *ob, float cursor[3], int centermode, int around)
+void ED_armature_origin_set(Main *bmain, 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 */
@@ -189,13 +190,13 @@ void ED_armature_origin_set(Main *bmain, Scene *scene, Object *ob, float cursor[
}
/* Turn the list into an armature */
- if (obedit == NULL) {
+ if (is_editmode == false) {
ED_armature_from_edit(bmain, 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);
}
@@ -318,10 +319,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);
@@ -631,25 +632,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;
@@ -664,7 +679,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];
@@ -673,7 +706,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);
@@ -711,7 +744,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);
@@ -1302,38 +1335,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 67b8b266269..7c0dd09a237 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -139,18 +139,6 @@ 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);
-
-/* ******************************************************* */
/* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */
/* pose_utils.c */
@@ -225,7 +213,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 +235,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 fb314fd4ac0..350dee07a2c 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"
@@ -379,7 +380,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 */
@@ -434,7 +435,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 3f2eefced7d..039bb7f1847 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);
@@ -204,23 +194,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);
@@ -229,7 +202,11 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_align", AKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+#ifdef USE_WM_KEYMAP_27X
WM_keymap_add_item(keymap, "ARMATURE_OT_calculate_roll", NKEY, KM_PRESS, KM_CTRL, 0);
+#else
+ WM_keymap_add_item(keymap, "ARMATURE_OT_calculate_roll", NKEY, KM_PRESS, KM_SHIFT, 0);
+#endif
WM_keymap_add_item(keymap, "ARMATURE_OT_roll_clear", RKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_switch_direction", FKEY, KM_PRESS, KM_ALT, 0);
@@ -240,7 +217,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_parent_clear", PKEY, KM_PRESS, KM_ALT, 0);
kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
+ RNA_enum_set(kmi->ptr, "action", SEL_SELECT);
+ kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_all", AKEY, KM_PRESS, KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_DESELECT);
kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
@@ -272,8 +251,12 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
+
WM_keymap_add_item(keymap, "ARMATURE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
+
+ WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
+
WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_forked", EKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_click_extrude", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
@@ -350,7 +333,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
#endif
kmi = WM_keymap_add_item(keymap, "POSE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
+ RNA_enum_set(kmi->ptr, "action", SEL_SELECT);
+ kmi = WM_keymap_add_item(keymap, "POSE_OT_select_all", AKEY, KM_PRESS, KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_DESELECT);
kmi = WM_keymap_add_item(keymap, "POSE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
@@ -372,7 +357,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "POSE_OT_select_linked", LKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "POSE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_select_mirror", FKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "POSE_OT_select_mirror", MKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
WM_keymap_add_item(keymap, "POSE_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
WM_keymap_add_item(keymap, "POSE_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
@@ -391,6 +376,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
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);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", ZKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.show_bone_select");
+
/* special transforms: */
/* 1) envelope/b-bone size */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index c211f9154ef..e0155a8c435 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,16 +393,17 @@ 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(bmain, arm);
ED_armature_edit_free(arm);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
@@ -569,6 +573,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 +597,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 +616,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 +631,8 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 4) fix links before depsgraph flushes */ // err... or after?
separated_armature_fix_links(bmain, 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 eb723671594..7602bccc48c 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;
+}
+
+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;
+}
- pchan = BLI_findlink(&ob->pose->chanbase, index);
- return pchan ? pchan->bone : NULL;
+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;
@@ -177,11 +254,31 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
rect.xmin = rect.xmax = xy[0];
rect.ymin = rect.ymax = xy[1];
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
+ hits = view3d_opengl_select(
+ &vc, buffer, MAXPICKBUF, &rect,
+ VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
+
+ *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);
+ }
- if (hits > 0)
- return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel, true);
+ 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 +291,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 +344,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,37 +390,43 @@ 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) {
- if (vc->v3d->drawtype > OB_WIRE) {
+ static int last_mval[2] = {-100, -100};
+
+ if (vc->v3d->shading.type > OB_WIRE) {
do_nearest = true;
if (len_manhattan_v2v2_int(vc->mval, last_mval) < 3) {
do_nearest = false;
@@ -331,58 +435,74 @@ static EditBone *get_nearest_editbonepoint(
copy_v2_v2_int(last_mval, vc->mval);
}
else {
- if (vc->v3d->drawtype > OB_WIRE) {
+ if (vc->v3d->shading.type > OB_WIRE) {
do_nearest = true;
}
}
/* 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);
+ const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP;
+
+ rcti rect;
+ BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
+ const int hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
+ 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, select_filter);
+
+ 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 +535,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 +593,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 +624,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 +720,15 @@ 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;
+ DEG_id_tag_update(&vc.scene->id, DEG_TAG_SELECT_UPDATE);
+ 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 +1441,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..63068e61ba3 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -43,11 +43,16 @@
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_mesh_iterators.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.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 +62,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 +90,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 +155,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 +189,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 +248,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.
@@ -258,7 +260,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
* into account and vertex weights can be mirrored.
*
* The mesh vertex positions used are either the final deformed coords
- * from the derivedmesh in weightpaint mode, the final subsurf coords
+ * from the evaluated mesh in weightpaint mode, the final subsurf coords
* when parenting, or simply the original mesh coords.
*/
@@ -272,12 +274,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);
@@ -371,15 +374,11 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
if (wpmode) {
- /* if in weight paint mode, use final verts from derivedmesh */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ /* if in weight paint mode, use final verts from evaluated mesh */
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
- if (dm->foreachMappedVert) {
- mesh_get_mapped_verts_coords(dm, verts, mesh->totvert);
- vertsfilled = 1;
- }
-
- dm->release(dm);
+ BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert);
+ vertsfilled = 1;
}
else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
/* is subsurf on? Lets use the verts on the limit surface then.
@@ -400,15 +399,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 +425,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 +453,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 c6cd9475008..c93bfb5d8c3 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"
@@ -680,11 +681,11 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
/* so all users of this armature should get rebuilt */
for (obt = bmain->object.first; obt; obt = obt->id.next) {
if (obt->data == arm) {
- BKE_pose_rebuild(obt, arm);
+ BKE_pose_rebuild(bmain, obt, 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_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
deleted file mode 100644
index 691da4cbd2b..00000000000
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ /dev/null
@@ -1,2663 +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 ============================================= */
-
-bool 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 bool 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;
- }
-}
-
-bool 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;
- }
-}
-
-bool 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 = (bool (*)(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..001c8ce215f 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -39,13 +40,16 @@
#include "BLT_translation.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_modifier.h"
+#include "BKE_bvhutils.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
#include "ED_mesh.h"
#include "ED_armature.h"
+#include "DEG_depsgraph.h"
+
#include "eigen_capi.h"
#include "meshlaplacian.h"
@@ -600,9 +604,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 +835,7 @@ typedef struct MeshDeformBind {
int size, size3;
/* meshes */
- DerivedMesh *cagedm;
+ Mesh *cagemesh;
float (*cagecos)[3];
float (*vertexcos)[3];
int totvert, totcagevert;
@@ -860,7 +865,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 +890,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 +956,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 +1133,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 +1449,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 +1462,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 +1578,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 +1594,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 bd0d2888568..6758f9d16ac 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 389a8423f23..3ae578279ca 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,14 +41,17 @@
#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_main.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"
@@ -59,6 +64,7 @@
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_object.h"
+#include "ED_view3d.h"
#include "UI_interface.h"
@@ -82,7 +88,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;
@@ -91,6 +97,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;
@@ -107,26 +115,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);
}
@@ -168,8 +181,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(Main *bmain, 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 */
@@ -177,8 +192,11 @@ void ED_pose_recalculate_paths(Main *bmain, Scene *scene, Object *ob)
animviz_get_object_motionpaths(ob, &targets);
/* recalculate paths, then free */
- animviz_calc_motionpaths(bmain, 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);
}
@@ -212,7 +230,6 @@ static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEven
*/
static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
Scene *scene = CTX_data_scene(C);
@@ -241,7 +258,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(bmain, scene, ob);
+ ED_pose_recalculate_paths(C, scene, ob);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -270,7 +287,8 @@ void POSE_OT_paths_calculate(wmOperatorType *ot)
RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End",
"Last frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
- RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items, 0,
+ RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items,
+ MOTIONPATH_BAKE_HEADS,
"Bake Location",
"Which point on the bones is used when calculating paths");
}
@@ -289,7 +307,6 @@ static bool pose_update_paths_poll(bContext *C)
static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
Scene *scene = CTX_data_scene(C);
@@ -298,7 +315,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(bmain, scene, ob);
+ ED_pose_recalculate_paths(C, scene, ob);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -596,7 +613,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");
@@ -608,34 +625,31 @@ static void pose_copy_menu(Scene *scene)
static int pose_flip_names_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- 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(bmain, 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(bmain, 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;
}
@@ -684,7 +698,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);
@@ -733,7 +747,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;
@@ -813,6 +827,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;
@@ -880,6 +895,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;
}
@@ -908,7 +924,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)
{
- bool layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool 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)
@@ -954,6 +970,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;
}
@@ -1009,7 +1026,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;
bool layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
@@ -1017,7 +1033,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);
@@ -1053,55 +1069,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)
@@ -1127,32 +1142,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)
@@ -1178,27 +1205,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)
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 9bb1caee067..2227bf33908 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_main.h"
@@ -56,6 +55,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"
@@ -503,6 +504,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;
@@ -617,6 +619,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;
@@ -1104,18 +1107,16 @@ 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 */
if (pld->state == PL_PREVIEW_RUNNING) {
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
- BLI_strncpy(pld->headerstr,
- IFACE_("PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again"),
- sizeof(pld->headerstr));
- ED_area_headerprint(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->sa, IFACE_("PoseLib Previewing Pose: [Showing Original Pose]"));
+ ED_workspace_status_text(C, IFACE_("Use Tab to start previewing poses again"));
}
else if (pld->searchstr[0]) {
char tempstr[65];
@@ -1139,17 +1140,17 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
IFACE_("PoseLib Previewing Pose: Filter - [%s] | "
- "Current Pose - \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change"),
+ "Current Pose - \"%s\""),
tempstr, markern);
- ED_area_headerprint(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->sa, pld->headerstr);
+ ED_workspace_status_text(C, IFACE_("Use ScrollWheel or PageUp/Down to change pose"));
}
else {
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- IFACE_("PoseLib Previewing Pose: \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change"),
+ IFACE_("PoseLib Previewing Pose: \"%s\""),
pld->marker->name);
- ED_area_headerprint(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->sa, pld->headerstr);
+ ED_workspace_status_text(C, NULL);
}
}
@@ -1599,7 +1600,8 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
TimeMarker *marker = pld->marker;
/* redraw the header so that it doesn't show any of our stuff anymore */
- ED_area_headerprint(pld->sa, NULL);
+ ED_area_status_text(pld->sa, NULL);
+ ED_workspace_status_text(C, NULL);
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
pose->flag |= POSE_DO_UNLOCK;
@@ -1612,9 +1614,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 */
@@ -1625,14 +1627,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 ecfaa41b0b5..72f0c68f660 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_slide.c b/source/blender/editors/armature/pose_slide.c
index b82535f013b..0a07af4ab43 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -705,7 +705,7 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
BLI_snprintf(status_str, sizeof(status_str), "%s: %d %% | %s", mode_str, (int)(pso->percentage * 100.0f), limits_str);
}
- ED_area_headerprint(pso->sa, status_str);
+ ED_area_status_text(pso->sa, status_str);
}
/* common code for invoke() methods */
@@ -857,7 +857,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case PADENTER:
{
/* return to normal cursor and header status */
- ED_area_headerprint(pso->sa, NULL);
+ ED_area_status_text(pso->sa, NULL);
WM_cursor_modal_restore(win);
/* insert keyframes as required... */
@@ -872,7 +872,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE:
{
/* return to normal cursor and header status */
- ED_area_headerprint(pso->sa, NULL);
+ ED_area_status_text(pso->sa, NULL);
WM_cursor_modal_restore(win);
/* reset transforms back to original state */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 2d8f5dbecbe..22c710dcda5 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,8 +73,10 @@
/* Pose Apply */
/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */
-static void applyarmature_fix_boneparents(Main *bmain, 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 */
@@ -83,7 +88,7 @@ static void applyarmature_fix_boneparents(Main *bmain, Scene *scene, Object *arm
*/
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);
}
}
@@ -93,8 +98,10 @@ static void applyarmature_fix_boneparents(Main *bmain, Scene *scene, Object *arm
static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ 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;
@@ -122,11 +129,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
@@ -142,7 +150,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);
@@ -156,17 +164,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;
@@ -190,13 +200,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(bmain, 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;
}
@@ -220,38 +231,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;
}
@@ -502,7 +516,6 @@ void POSE_OT_copy(wmOperatorType *ot)
static int pose_paste_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
Scene *scene = CTX_data_scene(C);
bPoseChannel *chan;
@@ -567,11 +580,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(bmain, scene, ob);
+ ED_pose_recalculate_paths(C, scene, ob);
}
/* Notifiers for updates, */
@@ -755,10 +768,8 @@ static void pchan_clear_transforms(bPoseChannel *pchan)
static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
void (*clear_func)(bPoseChannel *), const char default_ksName[])
{
- Main *bmain = CTX_data_main(C);
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)) {
@@ -767,47 +778,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(bmain, 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;
}
/* --------------- */
@@ -900,57 +934,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);
+ /* notifiers and updates */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
}
- 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 */
- 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 b390f3d0f75..e280284a9ce 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -39,12 +39,13 @@
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_depsgraph.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_context.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "WM_api.h"
@@ -183,6 +184,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
@@ -190,11 +192,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);
}
@@ -236,8 +238,6 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
/* perform autokeyframing after changes were made + confirmed */
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, Object *ob, ListBase *pfLinks, float cframe)
{
- Main *bmain = CTX_data_main(C);
-
/* insert keyframes as necessary if autokeyframing */
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
@@ -269,7 +269,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(bmain, 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__*/