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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_layer.h111
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/editmesh.c2
-rw-r--r--source/blender/blenkernel/intern/layer.c57
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c125
-rw-r--r--source/blender/blenkernel/intern/object.c39
-rw-r--r--source/blender/blenkernel/intern/object_update.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c67
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h1
-rw-r--r--source/blender/draw/intern/draw_armature.c2
-rw-r--r--source/blender/draw/intern/draw_manager.c7
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c9
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c4
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c4
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c3
-rw-r--r--source/blender/draw/modes/pose_mode.c4
-rw-r--r--source/blender/editors/armature/CMakeLists.txt1
-rw-r--r--source/blender/editors/armature/armature_add.c3
-rw-r--r--source/blender/editors/armature/armature_edit.c86
-rw-r--r--source/blender/editors/armature/armature_intern.h11
-rw-r--r--source/blender/editors/armature/armature_select.c221
-rw-r--r--source/blender/editors/armature/editarmature_undo.c81
-rw-r--r--source/blender/editors/armature/pose_edit.c3
-rw-r--r--source/blender/editors/armature/pose_select.c108
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/editcurve_undo.c77
-rw-r--r--source/blender/editors/include/ED_armature.h13
-rw-r--r--source/blender/editors/include/ED_mesh.h3
-rw-r--r--source/blender/editors/include/ED_object.h3
-rw-r--r--source/blender/editors/include/ED_undo.h5
-rw-r--r--source/blender/editors/include/ED_uvedit.h9
-rw-r--r--source/blender/editors/include/ED_view3d.h1
-rw-r--r--source/blender/editors/lattice/CMakeLists.txt1
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c77
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editmesh_select.c255
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c129
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c83
-rw-r--r--source/blender/editors/mesh/meshtools.c45
-rw-r--r--source/blender/editors/metaball/CMakeLists.txt1
-rw-r--r--source/blender/editors/metaball/editmball_undo.c77
-rw-r--r--source/blender/editors/object/object_edit.c162
-rw-r--r--source/blender/editors/object/object_modes.c3
-rw-r--r--source/blender/editors/screen/screen_context.c66
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c276
-rw-r--r--source/blender/editors/transform/transform.c761
-rw-r--r--source/blender/editors/transform/transform.h143
-rw-r--r--source/blender/editors/transform/transform_constraints.c50
-rw-r--r--source/blender/editors/transform/transform_conversions.c894
-rw-r--r--source/blender/editors/transform/transform_generics.c450
-rw-r--r--source/blender/editors/transform/transform_snap.c98
-rw-r--r--source/blender/editors/undo/ed_undo.c23
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c18
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h11
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c312
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c251
58 files changed, 3780 insertions, 1480 deletions
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 9c06ae4f40d..75fb4962bef 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -187,10 +187,20 @@ void BKE_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
void BKE_visible_objects_iterator_next(BLI_Iterator *iter);
void BKE_visible_objects_iterator_end(BLI_Iterator *iter);
+struct ObjectsInModeIteratorData {
+ int object_mode;
+ struct ViewLayer *view_layer;
+ struct Base *base_active;
+};
+
void BKE_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
void BKE_renderable_objects_iterator_next(BLI_Iterator *iter);
void BKE_renderable_objects_iterator_end(BLI_Iterator *iter);
+void BKE_view_layer_objects_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_objects_in_mode_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_objects_in_mode_iterator_end(BLI_Iterator *iter);
+
void BKE_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
void BKE_selected_bases_iterator_next(BLI_Iterator *iter);
void BKE_selected_bases_iterator_end(BLI_Iterator *iter);
@@ -217,6 +227,43 @@ void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_VISIBLE_OBJECT_END \
ITER_END
+
+#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _object_mode, _instance) \
+{ \
+ struct ObjectsInModeIteratorData data_ = { \
+ .object_mode = _object_mode, \
+ .view_layer = _view_layer, \
+ .base_active = _view_layer->basact, \
+ }; \
+ ITER_BEGIN(BKE_view_layer_objects_in_mode_iterator_begin, \
+ BKE_view_layer_objects_in_mode_iterator_next, \
+ BKE_view_layer_objects_in_mode_iterator_end, \
+ &data_, Base *, _instance)
+
+#define FOREACH_BASE_IN_MODE_END \
+ ITER_END; \
+} ((void)0)
+
+#define FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \
+ FOREACH_BASE_IN_MODE_BEGIN(_view_layer, OB_MODE_EDIT, _instance)
+
+#define FOREACH_BASE_IN_EDIT_MODE_END \
+ FOREACH_BASE_IN_MODE_END
+
+#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _object_mode, _instance) \
+ FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _object_mode, _base) { \
+ Object *_instance = _base->object;
+
+#define FOREACH_OBJECT_IN_MODE_END \
+ } FOREACH_BASE_IN_MODE_END
+
+#define FOREACH_OBJECT_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \
+ FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _base) { \
+ Object *_instance = _base->object;
+
+#define FOREACH_OBJECT_IN_EDIT_MODE_END \
+ } FOREACH_BASE_IN_EDIT_MODE_END
+
#define FOREACH_SELECTED_BASE_BEGIN(view_layer, _instance) \
ITER_BEGIN(BKE_selected_bases_iterator_begin, \
BKE_selected_bases_iterator_next, \
@@ -299,6 +346,70 @@ struct ObjectsRenderableIteratorData {
ITER_END; \
} ((void)0)
+
+/* layer_utils.c */
+
+struct ObjectsInModeParams {
+ int object_mode;
+ uint no_dup_data : 1;
+
+ bool (*filter_fn)(struct Object *ob, void *user_data);
+ void *filter_userdata;
+};
+
+Base **BKE_view_layer_array_from_bases_in_mode_params(
+ struct ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params);
+
+struct Object **BKE_view_layer_array_from_objects_in_mode_params(
+ struct ViewLayer *view_layer, uint *len,
+ const struct ObjectsInModeParams *params);
+
+#define BKE_view_layer_array_from_objects_in_mode(view_layer, r_len, ...) \
+ BKE_view_layer_array_from_objects_in_mode_params( \
+ view_layer, r_len, \
+ &(const struct ObjectsInModeParams)__VA_ARGS__)
+
+#define BKE_view_layer_array_from_bases_in_mode(view_layer, r_len, ...) \
+ BKE_view_layer_array_from_bases_in_mode_params( \
+ view_layer, r_len, \
+ &(const struct ObjectsInModeParams)__VA_ARGS__)
+
+bool BKE_view_layer_filter_edit_mesh_has_uvs(struct Object *ob, void *user_data);
+bool BKE_view_layer_filter_edit_mesh_has_edges(struct Object *ob, void *user_data);
+
+/* Utility macros that wrap common args (add more as needed). */
+
+#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT});
+
+#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, r_len) \
+ BKE_view_layer_array_from_bases_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT});
+
+#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true});
+
+#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, r_len) \
+ BKE_view_layer_array_from_bases_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true});
+
+#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true, \
+ .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs});
+
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index c698db2e8f5..c75bbf849a8 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -83,7 +83,9 @@ void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
bool BKE_object_exists_check(const struct Object *obtest);
bool BKE_object_is_in_editmode(const struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob);
+bool BKE_object_is_in_editmode_and_selected(const struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob);
+bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode);
typedef enum eObjectVisibilityCheck {
OB_VISIBILITY_CHECK_FOR_VIEWPORT,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 6a1c3ea883c..e8fd71c2b2d 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -167,6 +167,7 @@ set(SRC
intern/pointcache.c
intern/property.c
intern/layer.c
+ intern/layer_utils.c
intern/lightprobe.c
intern/report.c
intern/rigidbody.c
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index c95da3b2569..b63ab276b14 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -89,11 +89,13 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
/* sanity check */
+#if 0 /* disable in mutlti-object edit. */
#ifndef NDEBUG
if (((Mesh *)ob->data)->edit_btmesh) {
BLI_assert(((Mesh *)ob->data)->edit_btmesh->ob == ob);
}
#endif
+#endif
return ((Mesh *)ob->data)->edit_btmesh;
}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 50c7dc0c02f..5f24dd481e2 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -26,6 +26,7 @@
#include <string.h>
+#include "BLI_array.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
@@ -41,6 +42,7 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_workspace.h"
+#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -2235,6 +2237,61 @@ void BKE_renderable_objects_iterator_end(BLI_Iterator *UNUSED(iter))
/* Do nothing - iter->data was static allocated, we can't free it. */
}
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_objects_in_mode_iterator
+ * \{ */
+
+void BKE_view_layer_objects_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ struct ObjectsInModeIteratorData *data = data_in;
+ Base *base = data->base_active;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+ iter->data = data_in;
+ iter->current = base;
+}
+
+void BKE_view_layer_objects_in_mode_iterator_next(BLI_Iterator *iter)
+{
+ struct ObjectsInModeIteratorData *data = iter->data;
+ Base *base = iter->current;
+
+ if (base == data->base_active) {
+ /* first step */
+ base = data->view_layer->object_bases.first;
+ if (base == data->base_active) {
+ base = base->next;
+ }
+ }
+ else {
+ base = base->next;
+ }
+
+ while (base) {
+ if ((base->flag & BASE_SELECTED) != 0 &&
+ (base->object->type == data->base_active->object->type) &&
+ (base != data->base_active) &&
+ (base->object->mode & data->object_mode))
+ {
+ iter->current = base;
+ return;
+ }
+ base = base->next;
+ }
+ iter->valid = false;
+}
+
+void BKE_view_layer_objects_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
/* Evaluation */
/**
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
new file mode 100644
index 00000000000..94bac8a33d6
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -0,0 +1,125 @@
+/*
+ * ***** 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/blenkernel/intern/layer_utils.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_array.h"
+#include "BLI_listbase.h"
+
+#include "BKE_collection.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+Base **BKE_view_layer_array_from_bases_in_mode_params(
+ ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ if (params->no_dup_data) {
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ } FOREACH_BASE_IN_MODE_END;
+ }
+
+ Base **base_array = NULL;
+ BLI_array_declare(base_array);
+
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) {
+ if (params->filter_fn) {
+ if (!params->filter_fn(base_iter->object, params->filter_userdata)) {
+ continue;
+ }
+ }
+ if (params->no_dup_data) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ if (id->tag & LIB_TAG_DOIT) {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ BLI_array_append(base_array, base_iter);
+ } FOREACH_BASE_IN_MODE_END;
+
+ if (base_array != NULL) {
+ base_array = MEM_reallocN(base_array, sizeof(*base_array) * BLI_array_len(base_array));
+ }
+ *r_len = BLI_array_len(base_array);
+ return base_array;
+}
+
+Object **BKE_view_layer_array_from_objects_in_mode_params(
+ ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ Base **base_array = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, r_len, params);
+ if (base_array != NULL) {
+ for (uint i = 0; i < *r_len; i++) {
+ ((Object **)base_array)[i] = base_array[i]->object;
+ }
+ }
+ return (Object **)base_array;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_uvs(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV) != -1) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_edges(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (em->bm->totedge != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 875d716305f..081f9f15508 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -530,6 +530,15 @@ bool BKE_object_is_in_editmode(const Object *ob)
return false;
}
+bool BKE_object_is_in_editmode_and_selected(const Object *ob)
+{
+ if ((ob->flag & SELECT) && (BKE_object_is_in_editmode(ob))) {
+ return true;
+ }
+ return false;
+}
+
+
bool BKE_object_is_in_editmode_vgroup(const Object *ob)
{
return (OB_TYPE_SUPPORT_VGROUP(ob->type) &&
@@ -548,6 +557,36 @@ bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
return false;
}
+bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode)
+{
+ if (object_mode & OB_MODE_EDIT) {
+ if (BKE_object_is_in_editmode(ob)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_VERTEX_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_SCULPT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_POSE) {
+ if (ob->pose != NULL) {
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Return if the object is visible, as evaluated by depsgraph
*/
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index c70e07e6c4c..35ab4024f62 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -172,7 +172,15 @@ void BKE_object_handle_data_update(
switch (ob->type) {
case OB_MESH:
{
+#if 0
BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
+#else
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_btmesh : NULL;
+ if (em && em->ob != ob) {
+ em = NULL;
+ }
+#endif
+
uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
#ifdef WITH_FREESTYLE
/* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 9e03c28ba1b..8071637d95e 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -1160,7 +1160,7 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
}
}
-void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4])
{
const char htype_needed = bm->elem_index_dirty & htype;
@@ -1173,15 +1173,15 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & BM_VERT) {
- if (bm->elem_index_dirty & BM_VERT) {
+ if ((bm->elem_index_dirty & BM_VERT) || (elem_offset && elem_offset[0])) {
BMIter iter;
BMElem *ele;
- int index;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, index) {
- BM_elem_index_set(ele, index); /* set_ok */
+ int index = elem_offset ? elem_offset[0] : 0;
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_index_set(ele, index++); /* set_ok */
}
- BLI_assert(index == bm->totvert);
+ BLI_assert(elem_offset || index == bm->totvert);
}
else {
// printf("%s: skipping vert index calc!\n", __func__);
@@ -1189,15 +1189,15 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & BM_EDGE) {
- if (bm->elem_index_dirty & BM_EDGE) {
+ if ((bm->elem_index_dirty & BM_EDGE) || (elem_offset && elem_offset[1])) {
BMIter iter;
BMElem *ele;
- int index;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, index) {
- BM_elem_index_set(ele, index); /* set_ok */
+ int index = elem_offset ? elem_offset[1] : 0;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_index_set(ele, index++); /* set_ok */
}
- BLI_assert(index == bm->totedge);
+ BLI_assert(elem_offset || index == bm->totedge);
}
else {
// printf("%s: skipping edge index calc!\n", __func__);
@@ -1205,19 +1205,19 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & (BM_FACE | BM_LOOP)) {
- if (bm->elem_index_dirty & (BM_FACE | BM_LOOP)) {
+ if ((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) || (elem_offset && (elem_offset[2] || elem_offset[3]))) {
BMIter iter;
BMElem *ele;
const bool update_face = (htype & BM_FACE) && (bm->elem_index_dirty & BM_FACE);
const bool update_loop = (htype & BM_LOOP) && (bm->elem_index_dirty & BM_LOOP);
- int index;
- int index_loop = 0;
+ int index_loop = elem_offset ? elem_offset[2] : 0;
+ int index = elem_offset ? elem_offset[3] : 0;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, index) {
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
if (update_face) {
- BM_elem_index_set(ele, index); /* set_ok */
+ BM_elem_index_set(ele, index++); /* set_ok */
}
if (update_loop) {
@@ -1230,9 +1230,9 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
}
- BLI_assert(index == bm->totface);
+ BLI_assert(elem_offset || !update_face || index == bm->totface);
if (update_loop) {
- BLI_assert(index_loop == bm->totloop);
+ BLI_assert(elem_offset || !update_loop || index_loop == bm->totloop);
}
}
else {
@@ -1242,6 +1242,37 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
finally:
bm->elem_index_dirty &= ~htype;
+ if (elem_offset) {
+ if (htype & BM_VERT) {
+ elem_offset[0] += bm->totvert;
+ if (elem_offset[0] != bm->totvert) {
+ bm->elem_index_dirty |= BM_VERT;
+ }
+ }
+ if (htype & BM_EDGE) {
+ elem_offset[1] += bm->totedge;
+ if (elem_offset[1] != bm->totedge) {
+ bm->elem_index_dirty |= BM_EDGE;
+ }
+ }
+ if (htype & BM_LOOP) {
+ elem_offset[2] += bm->totloop;
+ if (elem_offset[2] != bm->totloop) {
+ bm->elem_index_dirty |= BM_LOOP;
+ }
+ }
+ if (htype & BM_FACE) {
+ elem_offset[3] += bm->totface;
+ if (elem_offset[3] != bm->totface) {
+ bm->elem_index_dirty |= BM_FACE;
+ }
+ }
+ }
+}
+
+void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
+{
+ BM_mesh_elem_index_ensure_ex(bm, htype, NULL);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index d449aac04f5..3ebe6535a8b 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -60,6 +60,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4]);
void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag);
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func,
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index c14fe70e0c3..fe87e7f17fd 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -1228,7 +1228,7 @@ static void draw_armature_edit(Object *ob)
const bool show_text = DRW_state_show_text();
- for (eBone = arm->edbo->first, index = 0; eBone; eBone = eBone->next, index++) {
+ for (eBone = arm->edbo->first, index = ob->select_color; eBone; eBone = eBone->next, index += 0x10000) {
if (eBone->layer & arm->layer) {
if ((eBone->flag & BONE_HIDDEN_A) == 0) {
const int select_id = is_select ? index : (unsigned int)-1;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 6ba1225b687..420841e2efa 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1554,7 +1554,14 @@ void DRW_draw_select_loop(
drw_engines_cache_init();
if (use_obedit) {
+#if 0
drw_engines_cache_populate(obact);
+#else
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, obact->mode, ob_iter) {
+ drw_engines_cache_populate(ob_iter);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+#endif
}
else {
DEG_OBJECT_ITER_BEGIN(
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
index 73a4fb1e9e6..b33ebd8ba60 100644
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -28,6 +28,8 @@
#include "DNA_curve_types.h"
+#include "BKE_object.h"
+
/* If builtin shaders are needed */
#include "GPU_shader.h"
#include "GPU_batch.h"
@@ -233,7 +235,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
UNUSED_VARS(psl, stl);
if (ob->type == OB_CURVE) {
- if (ob == draw_ctx->object_edit) {
+#if 0
+ if (ob == draw_ctx->object_edit)
+#else
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode_and_selected(ob))
+#endif
+ {
Curve *cu = ob->data;
/* Get geometry cache */
struct Gwn_Batch *geom;
diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c
index 0268f4eb453..e8628711ffd 100644
--- a/source/blender/draw/modes/edit_lattice_mode.c
+++ b/source/blender/draw/modes/edit_lattice_mode.c
@@ -26,6 +26,8 @@
#include "DRW_engine.h"
#include "DRW_render.h"
+#include "BKE_object.h"
+
/* If builtin shaders are needed */
#include "GPU_shader.h"
@@ -192,7 +194,7 @@ static void EDIT_LATTICE_cache_populate(void *vedata, Object *ob)
UNUSED_VARS(psl);
if (ob->type == OB_LATTICE) {
- if (ob == draw_ctx->object_edit) {
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode_and_selected(ob)) {
/* Get geometry cache */
struct Gwn_Batch *geom;
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index 4bd69941809..c465fa38f04 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -37,6 +37,8 @@
#include "edit_mesh_mode_intern.h" /* own include */
+#include "BKE_object.h"
+
extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
extern struct GlobalsUboStorage ts; /* draw_common.c */
@@ -448,7 +450,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
struct Gwn_Batch *geom;
if (ob->type == OB_MESH) {
- if (ob == draw_ctx->object_edit) {
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode_and_selected(ob)) {
const Mesh *me = ob->data;
IDProperty *ces_mode_ed = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_EDIT, "");
bool do_occlude_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "show_occlude_wire");
diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c
index bcabeef5bc3..f7b7113a4d6 100644
--- a/source/blender/draw/modes/edit_metaball_mode.c
+++ b/source/blender/draw/modes/edit_metaball_mode.c
@@ -28,6 +28,7 @@
#include "DNA_meta_types.h"
+#include "BKE_object.h"
#include "BKE_mball.h"
/* If builtin shaders are needed */
@@ -171,7 +172,7 @@ static void EDIT_METABALL_cache_populate(void *vedata, Object *ob)
const DRWContextState *draw_ctx = DRW_context_state_get();
DRWShadingGroup *group = stl->g_data->group;
- if (ob == draw_ctx->object_edit) {
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode_and_selected(ob)) {
MetaBall *mb = ob->data;
const bool is_select = DRW_state_is_select();
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
index 749c3e71368..1d3d31ab54d 100644
--- a/source/blender/draw/modes/pose_mode.c
+++ b/source/blender/draw/modes/pose_mode.c
@@ -139,7 +139,9 @@ bool DRW_pose_mode_armature(Object *ob, Object *active_ob)
const DRWContextState *draw_ctx = DRW_context_state_get();
/* Pode armature is handled by pose mode engine. */
- if ((ob == active_ob) && ((draw_ctx->object_mode & OB_MODE_POSE) != 0)) {
+ if (((ob == active_ob) || (ob->base_flag & BASE_SELECTED)) &&
+ ((draw_ctx->object_mode & OB_MODE_POSE) != 0))
+ {
return true;
}
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 4301fe6582f..8a40ea3b383 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
../../../../intern/eigen
../../../../intern/glew-mx
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index cb072bee345..36dded5ed5e 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -1074,7 +1074,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 +1082,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 75b80627dff..2335e29aca8 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -48,6 +48,7 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_global.h"
#include "BKE_report.h"
#include "BKE_object.h"
@@ -630,25 +631,39 @@ static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
/* bone adding between selected joints */
static int armature_fill_bones_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = (obedit) ? obedit->data : NULL;
+ Object *obedit_active = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase points = {NULL, NULL};
EditBone *newbone = NULL;
int count;
+ bool mixed_object_error = false;
/* sanity checks */
- if (ELEM(NULL, obedit, arm))
+ if (ELEM(NULL, obedit_active, obedit_active->data)) {
return OPERATOR_CANCELLED;
+ }
/* loop over all bones, and only consider if visible */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ bArmature *arm = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter)
{
- if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
+ bool check = false;
+ if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
fill_add_joint(ebone, 0, &points);
- if (ebone->flag & BONE_TIPSEL)
+ check = true;
+ }
+ if (ebone->flag & BONE_TIPSEL) {
fill_add_joint(ebone, 1, &points);
+ check = true;
+ }
+
+ if (check) {
+ if (arm && (arm != arm_iter)) {
+ mixed_object_error = true;
+ }
+ arm = arm_iter;
+ }
}
CTX_DATA_END;
@@ -658,12 +673,30 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
* 3+) error (a smarter method involving finding chains needs to be worked out
*/
count = BLI_listbase_count(&points);
-
+
if (count == 0) {
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];
@@ -1301,18 +1334,23 @@ 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;
-
+
+ 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) {
@@ -1325,14 +1363,20 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
}
}
}
-
- if (!changed)
- 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);
+ if (changed) {
+ changed_multi = true;
+
+ 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);
+ }
+ }
+
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 0ba720a17d0..575d1597cc4 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -248,10 +248,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 Base *base, struct Object *obedit, 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_select.c b/source/blender/editors/armature/armature_select.c
index 587cafa6d48..63864e75edc 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"
@@ -40,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_action.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
#include "BIF_gl.h"
@@ -63,26 +66,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
-
- pchan = BLI_findlink(&ob->pose->chanbase, index);
- return pchan ? pchan->bone : NULL;
+ 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;
+}
+
+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(
- Base *base, Object *obedit, 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)
{
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;
@@ -93,15 +154,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->object->select_color == (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
@@ -115,14 +175,12 @@ 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
sel = !(ebone->flag & BONE_SELECTED);
-
+
data = ebone;
}
@@ -131,11 +189,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;
}
}
@@ -143,12 +205,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;
+ }
}
}
}
@@ -156,16 +225,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)
{
EvaluationContext eval_ctx;
ViewContext vc;
@@ -182,8 +257,20 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
hits = view3d_opengl_select(&eval_ctx, &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
+ *r_base = NULL;
+
if (hits > 0) {
- return get_bone_from_selectbuffer(vc.view_layer->basact, vc.obedit, buffer, hits, findunsel, true);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_mode(
+ eval_ctx.view_layer, &bases_len, {
+ .object_mode = vc.obedit ? OB_MODE_EDIT : OB_MODE_POSE,
+ .no_dup_data = 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;
}
@@ -197,16 +284,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) {
@@ -249,7 +337,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;
}
@@ -295,7 +383,8 @@ 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(
const EvaluationContext *eval_ctx, 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;
@@ -371,9 +460,11 @@ static EditBone *get_nearest_editbonepoint(
cache_end:
view3d_opengl_select_cache_end();
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(eval_ctx->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];
@@ -382,10 +473,11 @@ cache_end:
for (i = 0; i < hits; i++) {
hitresult = buffer[3 + (i * 4)];
if (!(hitresult & BONESEL_NOSEL)) {
+ Base *base = NULL;
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ arm = base->object->data;
+
int dep;
-
- ebone = BLI_findlink(arm->edbo, hitresult & ~BONESEL_ANY);
-
/* clicks on bone points get advantage */
if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
/* but also the unselected one */
@@ -425,11 +517,13 @@ cache_end:
}
}
}
-
+
if (!(besthitresult & BONESEL_NOSEL)) {
-
- ebone = BLI_findlink(arm->edbo, besthitresult & ~BONESEL_ANY);
-
+ Base *base = NULL;
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ arm = base->object->data;
+ *r_base = base;
+
*r_selmask = 0;
if (besthitresult & BONESEL_ROOT)
*r_selmask |= BONE_ROOTSEL;
@@ -441,6 +535,7 @@ cache_end:
}
}
*r_selmask = 0;
+ *r_base = NULL;
return NULL;
}
@@ -469,6 +564,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)
{
@@ -483,11 +595,11 @@ 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);
EvaluationContext eval_ctx;
ViewContext vc;
EditBone *nearBone = NULL;
int selmask;
+ Base *basact = NULL;
CTX_data_eval_ctx(C, &eval_ctx);
ED_view3d_viewcontext_init(C, &vc);
@@ -498,12 +610,16 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
return true;
}
- nearBone = get_nearest_editbonepoint(&eval_ctx, &vc, true, true, &selmask);
+ nearBone = get_nearest_editbonepoint(&eval_ctx, &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(eval_ctx.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,
@@ -581,9 +697,14 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
if (ebone_select_flag(nearBone)) {
arm->act_edbone = nearBone;
}
+
+ if (eval_ctx.view_layer->basact != basact) {
+ eval_ctx.view_layer->basact = basact;
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, vc.scene);
+ }
}
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
return true;
}
@@ -1296,17 +1417,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/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 217de06d99b..f6f97af32b9 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -27,26 +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_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
* \{ */
@@ -121,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)
@@ -138,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;
}
@@ -152,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);
- DEG_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/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 520ecc797aa..ea93e024f8e 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -1015,7 +1015,6 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven
static int armature_bone_layers_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
PointerRNA ptr;
int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
@@ -1023,7 +1022,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);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 1c23f71233d..b6f1e101291 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -145,7 +146,9 @@ bool ED_armature_pose_select_pick_with_buffer(
Object *ob_act = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- nearBone = get_bone_from_selectbuffer(base, obedit, buffer, hits, 1, do_nearest);
+ /* 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)) {
@@ -166,7 +169,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_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ ED_pose_deselect_all_multi(objects, objects_len, SEL_DESELECT, true);
+ MEM_SAFE_FREE(objects);
+ }
nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = nearBone;
}
@@ -252,6 +260,43 @@ 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];
+ ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility);
+ }
+}
+
/* ***************** Selections ********************** */
static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
@@ -278,17 +323,18 @@ 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) {
@@ -310,14 +356,14 @@ 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. */
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -354,27 +400,31 @@ 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);
+ }
+ 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)) {
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
return OPERATOR_FINISHED;
}
@@ -450,13 +500,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;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ Object *ob_prev = NULL;
+
+ 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);
@@ -472,6 +522,16 @@ 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);
+ }
+ ob_prev = ob;
+ }
}
}
}
@@ -487,14 +547,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. */
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 85daa7e44e5..301d333ebdb 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
../../../../intern/glew-mx
../../../../extern/curve_fit_nd
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 4eb2abaefad..ad17331853b 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -22,12 +22,14 @@
* \ingroup edcurve
*/
+#include "MEM_guardedalloc.h"
+
+#include "CLG_log.h"
+
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_anim_types.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_array_utils.h"
@@ -35,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_animsys.h"
#include "BKE_undo_system.h"
@@ -42,6 +45,7 @@
#include "DEG_depsgraph.h"
#include "ED_object.h"
+#include "ED_undo.h"
#include "ED_util.h"
#include "ED_curve.h"
@@ -50,6 +54,9 @@
#include "curve_intern.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.curve"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -187,13 +194,19 @@ static Object *editcurve_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct CurveUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct CurveUndoStep_Elem {
UndoRefID_Object obedit_ref;
UndoCurve data;
+} CurveUndoStep_Elem;
+
+typedef struct CurveUndoStep {
+ UndoStep step;
+ CurveUndoStep_Elem *elems;
+ uint elems_len;
} CurveUndoStep;
static bool curve_undosys_poll(bContext *C)
@@ -205,9 +218,23 @@ static bool curve_undosys_poll(bContext *C)
static bool curve_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
CurveUndoStep *us = (CurveUndoStep *)us_p;
- us->obedit_ref.ptr = editcurve_object_from_context(C);
- undocurve_from_editcurve(&us->data, us->obedit_ref.ptr->data, us->obedit_ref.ptr->shapenr);
- 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];
+ CurveUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ undocurve_from_editcurve(&elem->data, ob->data, ob->shapenr);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -218,23 +245,47 @@ static void curve_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UN
BLI_assert(curve_undosys_poll(C));
CurveUndoStep *us = (CurveUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- undocurve_to_editcurve(&us->data, obedit->data, &obedit->shapenr);
- DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ CurveUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ Curve *cu = obedit->data;
+ if (cu->editnurb == 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;
+ }
+ undocurve_to_editcurve(&elem->data, obedit->data, &obedit->shapenr);
+ 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 curve_undosys_step_free(UndoStep *us_p)
{
CurveUndoStep *us = (CurveUndoStep *)us_p;
- undocurve_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ CurveUndoStep_Elem *elem = &us->elems[i];
+ undocurve_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void curve_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
CurveUndoStep *us = (CurveUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ CurveUndoStep_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/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 186ca5313e5..e6284cb1656 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -142,19 +142,29 @@ void ED_armature_edit_free(struct bArmature *arm);
void ED_armature_edit_deselect_all(struct Object *obedit);
void ED_armature_edit_deselect_all_visible(struct Object *obedit);
+void ED_armature_edit_deselect_all_multi(struct Object **objects, uint objects_len);
+void ED_armature_edit_deselect_all_visible_multi(struct Object **objects, uint objects_len);
+
bool ED_armature_pose_select_pick_with_buffer(
struct ViewLayer *view_layer, struct Base *base, const unsigned int *buffer, short hits,
bool extend, bool deselect, bool toggle, bool do_nearest);
bool ED_armature_edit_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
int join_armature_exec(struct bContext *C, struct wmOperator *op);
-struct Bone *ED_armature_bone_find_index(struct Object *ob, int index);
float ED_armature_ebone_roll_to_vector(const EditBone *bone, const float new_up_axis[3], const bool axis_only);
EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone *ebo);
void ED_armature_edit_sync_selection(struct ListBase *edbo);
void ED_armature_edit_validate_active(struct bArmature *arm);
+struct Base *ED_armature_base_and_ebone_from_select_buffer(
+ struct Base **bases, uint bases_len, int hit, struct EditBone **r_ebone);
+struct Object *ED_armature_object_and_ebone_from_select_buffer(
+ struct Object **objects, uint objects_len, int hit, struct EditBone **r_ebone);
+
+struct Base *ED_armature_base_and_bone_from_select_buffer(
+ struct Base **bases, uint bases_len, int hit, struct Bone **r_bone);
+
EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm, float length, bool view_aligned);
EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name);
@@ -211,6 +221,7 @@ bool ED_object_posemode_exit(struct bContext *C, struct Object *ob);
bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_enter(struct bContext *C, struct Object *ob);
void ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
+void ED_pose_deselect_all_multi(struct Object **objects, uint objects_len, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
void ED_pose_recalculate_paths(struct bContext *C, struct Scene *scene, struct Object *ob);
struct Object *ED_pose_object_from_context(struct bContext *C);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 3217433204e..d3f2e1fff85 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -340,6 +340,9 @@ struct MDeformVert *ED_mesh_active_dvert_get_em(struct Object *ob, struct BMVert
struct MDeformVert *ED_mesh_active_dvert_get_ob(struct Object *ob, int *r_index);
struct MDeformVert *ED_mesh_active_dvert_get_only(struct Object *ob);
+void EDBM_mesh_stats_multi(struct Object **objects, const uint objects_len, int totelem[3], int totelem_sel[3]);
+void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, const uint objects_len, const char htype);
+
#define ED_MESH_PICK_DEFAULT_VERT_SIZE 50
#define ED_MESH_PICK_DEFAULT_FACE_SIZE 3
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 83119062203..bfc3325d7eb 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -124,10 +124,13 @@ enum {
EM_WAITCURSOR = (1 << 1),
EM_DO_UNDO = (1 << 2),
EM_IGNORE_LAYER = (1 << 3),
+ EM_NO_CONTEXT = (1 << 4),
};
void ED_object_editmode_exit_ex(
struct bContext *C, struct Scene *scene, struct Object *obedit, int flag);
void ED_object_editmode_exit(struct bContext *C, int flag);
+
+void ED_object_editmode_enter_ex(struct Scene *scene, struct Object *ob, int flag);
void ED_object_editmode_enter(struct bContext *C, int flag);
bool ED_object_editmode_load(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h
index b3814ab5899..43ffb091666 100644
--- a/source/blender/editors/include/ED_undo.h
+++ b/source/blender/editors/include/ED_undo.h
@@ -26,6 +26,7 @@
#define __ED_UNDO_H__
struct bContext;
+struct CLG_LogRef;
struct wmOperator;
struct wmOperatorType;
struct UndoStack;
@@ -53,6 +54,10 @@ bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
struct UndoStack *ED_undo_stack_get(void);
+/* helpers */
+void ED_undo_object_set_active_or_warn(
+ struct ViewLayer *view_layer, struct Object *ob, const char *info, struct CLG_LogRef *log);
+
/* undo_system_types.c */
void ED_undosys_type_init(void);
void ED_undosys_type_free(void);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 2a5ad494643..fd532e70478 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -119,17 +119,20 @@ void ED_uvedit_live_unwrap_end(short cancel);
void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
void ED_uvedit_pack_islands(
-struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
+ struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
+void ED_uvedit_pack_islands_multi(
+ struct Scene *scene, struct Object **objects, const uint objects_len,
+ bool selected, bool correct_aspect, bool do_rotate);
void ED_uvedit_unwrap_cube_project(
struct BMesh *bm, float cube_size, bool use_select, const float center[3]);
/* single call up unwrap using scene settings, used for edge tag unwrapping */
-void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
+void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel, const bool pack);
/* uvedit_draw.c */
void ED_image_draw_cursor(
-struct ARegion *ar, const float cursor[2]);
+ struct ARegion *ar, const float cursor[2]);
void ED_uvedit_draw_main(
struct SpaceImage *sima,
struct ARegion *ar, struct Scene *scene, struct ViewLayer *view_layer,
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 7f18c10f970..c5b99013610 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -352,6 +352,7 @@ int view3d_opengl_select(
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
+void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data);
diff --git a/source/blender/editors/lattice/CMakeLists.txt b/source/blender/editors/lattice/CMakeLists.txt
index eaf837cf978..2207e0fa736 100644
--- a/source/blender/editors/lattice/CMakeLists.txt
+++ b/source/blender/editors/lattice/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index 58fa08e5aa9..cbd89016b44 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -33,6 +33,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "BLI_utildefines.h"
#include "BLI_array_utils.h"
@@ -42,12 +44,14 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
#include "DEG_depsgraph.h"
#include "ED_object.h"
#include "ED_lattice.h"
+#include "ED_undo.h"
#include "ED_util.h"
#include "WM_types.h"
@@ -55,6 +59,9 @@
#include "lattice_intern.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.lattice"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -124,13 +131,19 @@ static Object *editlatt_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct LatticeUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct LatticeUndoStep_Elem {
UndoRefID_Object obedit_ref;
UndoLattice data;
+} LatticeUndoStep_Elem;
+
+typedef struct LatticeUndoStep {
+ UndoStep step;
+ LatticeUndoStep_Elem *elems;
+ uint elems_len;
} LatticeUndoStep;
static bool lattice_undosys_poll(bContext *C)
@@ -141,10 +154,24 @@ static bool lattice_undosys_poll(bContext *C)
static bool lattice_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- us->obedit_ref.ptr = editlatt_object_from_context(C);
- Lattice *lt = us->obedit_ref.ptr->data;
- undolatt_from_editlatt(&us->data, lt->editlatt);
- 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];
+ LatticeUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ Lattice *lt = ob->data;
+ undolatt_from_editlatt(&elem->data, lt->editlatt);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -155,25 +182,47 @@ static void lattice_undosys_step_decode(struct bContext *C, UndoStep *us_p, int
BLI_assert(lattice_undosys_poll(C));
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- Lattice *lt = obedit->data;
- EditLatt *editlatt = lt->editlatt;
- undolatt_to_editlatt(&us->data, editlatt);
- DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ LatticeUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ Lattice *lt = obedit->data;
+ if (lt->editlatt == 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;
+ }
+ undolatt_to_editlatt(&elem->data, lt->editlatt);
+ 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 lattice_undosys_step_free(UndoStep *us_p)
{
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- undolatt_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ LatticeUndoStep_Elem *elem = &us->elems[i];
+ undolatt_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void lattice_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ LatticeUndoStep_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/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 3877838ec54..eae6b7192d7 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
../../../../intern/glew-mx
)
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 87937fd4146..20cebc9d4b9 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -45,6 +45,7 @@
#include "BKE_report.h"
#include "BKE_paint.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -917,7 +918,7 @@ BMFace *EDBM_face_find_nearest(const struct EvaluationContext *eval_ctx, ViewCon
*/
static int unified_findnearest(
const struct EvaluationContext *eval_ctx, ViewContext *vc,
- BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
+ Base **r_base, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
{
BMEditMesh *em = vc->em;
static short mval_prev[2] = {-1, -1};
@@ -934,32 +935,70 @@ static int unified_findnearest(
BMEdge *eed = NULL;
BMFace *efa = NULL;
+ /* TODO(campbell): perform selection as one pass
+ * instead of many smaller passes (which doesn't work for zbuf occlusion). */
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(eval_ctx->view_layer, &bases_len);
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- ED_view3d_backbuf_validate(eval_ctx, vc);
if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) {
float dist_center = 0.0f;
float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL;
- efa = EDBM_face_find_nearest_ex(eval_ctx, vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
- if (efa && dist_center_p) {
- dist = min_ff(dist_margin, dist_center);
- }
+
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ ED_view3d_backbuf_validate(eval_ctx, vc);
+
+ BMFace *efa_test = EDBM_face_find_nearest_ex(eval_ctx, vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
+ if (efa && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ if (efa_test) {
+ *r_base = base_iter;
+ efa = efa_test;
+ }
+ } /* bases */
}
if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
float dist_center = 0.0f;
float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
- eed = EDBM_edge_find_nearest_ex(eval_ctx, vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
- if (eed && dist_center_p) {
- dist = min_ff(dist_margin, dist_center);
- }
+
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ ED_view3d_backbuf_validate(eval_ctx, vc);
+ BMEdge *eed_test = EDBM_edge_find_nearest_ex(eval_ctx, vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
+ if (eed && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ if (eed_test) {
+ *r_base = base_iter;
+ eed = eed_test;
+ }
+ } /* bases */
}
if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) {
- eve = EDBM_vert_find_nearest_ex(eval_ctx, vc, &dist, true, use_cycle);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ ED_view3d_backbuf_validate(eval_ctx, vc);
+ BMVert *eve_test = EDBM_vert_find_nearest_ex(eval_ctx, vc, &dist, true, use_cycle);
+ if (eve_test) {
+ *r_base = base_iter;
+ eve = eve_test;
+ }
+ } /* bases */
}
+ MEM_SAFE_FREE(bases);
+
/* return only one of 3 pointers, for frontbuffer redraws */
if (eve) {
efa = NULL; eed = NULL;
@@ -1804,27 +1843,43 @@ void MESH_OT_edgering_select(wmOperatorType *ot)
static int edbm_select_all_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int action = RNA_enum_get(op->ptr, "action");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int action = RNA_enum_get(op->ptr, "action");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) {
+ action = SEL_DESELECT;
+ break;
+ }
+ }
+ }
- switch (action) {
- case SEL_TOGGLE:
- EDBM_select_toggle_all(em);
- break;
- case SEL_SELECT:
- EDBM_flag_enable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_DESELECT:
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_INVERT:
- EDBM_select_swap(em);
- EDBM_selectmode_flush(em);
- break;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ switch (action) {
+ case SEL_SELECT:
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_DESELECT:
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_INVERT:
+ EDBM_select_swap(em);
+ EDBM_selectmode_flush(em);
+ break;
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_SAFE_FREE(objects);
return OPERATOR_FINISHED;
}
@@ -1896,6 +1951,8 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
{
EvaluationContext eval_ctx;
ViewContext vc;
+
+ Base *basact = NULL;
BMVert *eve = NULL;
BMEdge *eed = NULL;
BMFace *efa = NULL;
@@ -1906,11 +1963,23 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
- if (unified_findnearest(&eval_ctx, &vc, &eve, &eed, &efa)) {
+ if (unified_findnearest(&eval_ctx, &vc, &basact, &eve, &eed, &efa)) {
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
/* Deselect everything */
- if (extend == false && deselect == false && toggle == false)
- EDBM_flag_disable_all(vc.em, BM_ELEM_SELECT);
+ if (extend == false && deselect == false && toggle == false) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(eval_ctx.view_layer, &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT);
+ if (basact->object != ob_iter) {
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ }
+ }
+ MEM_SAFE_FREE(objects);
+ }
if (efa) {
if (extend) {
@@ -2020,7 +2089,14 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
}
+ /* Changing active object is handy since it allows us to
+ * switch UV layers, vgroups for eg. */
+ if (eval_ctx.view_layer->basact != basact) {
+ eval_ctx.view_layer->basact = basact;
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, vc.scene);
+ }
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
+
return true;
}
@@ -2242,11 +2318,14 @@ bool EDBM_selectmode_toggle(
bContext *C, const short selectmode_new,
const int action, const bool use_extend, const bool use_expand)
{
+ EvaluationContext eval_ctx;
ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = NULL;
bool ret = false;
+ CTX_data_eval_ctx(C, &eval_ctx);
+
if (obedit && obedit->type == OB_MESH) {
em = BKE_editmesh_from_object(obedit);
}
@@ -2255,6 +2334,7 @@ bool EDBM_selectmode_toggle(
return ret;
}
+ bool only_update = false;
switch (action) {
case -1:
/* already set */
@@ -2262,21 +2342,24 @@ bool EDBM_selectmode_toggle(
case 0: /* disable */
/* check we have something to do */
if ((em->selectmode & selectmode_new) == 0) {
- return false;
+ only_update = true;
+ break;
}
em->selectmode &= ~selectmode_new;
break;
case 1: /* enable */
/* check we have something to do */
if ((em->selectmode & selectmode_new) != 0) {
- return false;
+ only_update = true;
+ break;
}
em->selectmode |= selectmode_new;
break;
case 2: /* toggle */
/* can't disable this flag if its the only one set */
if (em->selectmode == selectmode_new) {
- return false;
+ only_update = true;
+ break;
}
em->selectmode ^= selectmode_new;
break;
@@ -2285,10 +2368,30 @@ bool EDBM_selectmode_toggle(
break;
}
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(eval_ctx.view_layer, &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ if (em_iter != em) {
+ em_iter->selectmode = em->selectmode;
+ }
+ }
+
+ if (only_update) {
+ MEM_SAFE_FREE(objects);
+ return false;
+ }
+
if (use_extend == 0 || em->selectmode == 0) {
if (use_expand) {
const short selmode_max = highest_order_bit_s(ts->selectmode);
- EDBM_selectmode_convert(em, selmode_max, selectmode_new);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new);
+ }
}
}
@@ -2297,24 +2400,18 @@ bool EDBM_selectmode_toggle(
if (use_extend == 0 || em->selectmode == 0) {
em->selectmode = SCE_SELECT_VERTEX;
}
- ts->selectmode = em->selectmode;
- EDBM_selectmode_set(em);
ret = true;
break;
case SCE_SELECT_EDGE:
if (use_extend == 0 || em->selectmode == 0) {
em->selectmode = SCE_SELECT_EDGE;
}
- ts->selectmode = em->selectmode;
- EDBM_selectmode_set(em);
ret = true;
break;
case SCE_SELECT_FACE:
if (use_extend == 0 || em->selectmode == 0) {
em->selectmode = SCE_SELECT_FACE;
}
- ts->selectmode = em->selectmode;
- EDBM_selectmode_set(em);
ret = true;
break;
default:
@@ -2323,10 +2420,18 @@ bool EDBM_selectmode_toggle(
}
if (ret == true) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ ts->selectmode = em->selectmode;
+ em = NULL;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ EDBM_selectmode_set(em_iter);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ }
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
}
+ MEM_SAFE_FREE(objects);
return ret;
}
@@ -2528,7 +2633,7 @@ static bool select_linked_delimit_test(
* Gets the default from the operator fallback to own last-used value
* (selected based on mode)
*/
-static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode)
+static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode)
{
static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
@@ -2594,17 +2699,27 @@ static void select_linked_delimit_end(BMEditMesh *em)
static int edbm_select_linked_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+#ifdef USE_LINKED_SELECT_DEFAULT_HACK
+ const int delimit_init = select_linked_delimit_default_from_op(op, scene->toolsettings->selectmode);
+#else
+ const int delimit_init = RNA_enum_get(op->ptr, "delimit");
+#endif
+
+ 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];
+
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMIter iter;
BMWalker walker;
-#ifdef USE_LINKED_SELECT_DEFAULT_HACK
- int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
-#else
- int delimit = RNA_enum_get(op->ptr, "delimit");
-#endif
+ int delimit = delimit_init;
select_linked_delimit_validate(bm, &delimit);
@@ -2761,6 +2876,10 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ } /* objects */
+
+ MEM_SAFE_FREE(objects);
+
return OPERATOR_FINISHED;
}
@@ -2902,11 +3021,9 @@ static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, in
static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *obedit = CTX_data_edit_object(C);
EvaluationContext eval_ctx;
ViewContext vc;
- BMEditMesh *em;
- BMesh *bm;
+ Base *basact = NULL;
BMVert *eve;
BMEdge *eed;
BMFace *efa;
@@ -2923,25 +3040,39 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
/* setup view context for argument to callbacks */
CTX_data_eval_ctx(C, &eval_ctx);
em_setup_viewcontext(C, &vc);
- em = vc.em;
- bm = em->bm;
- if (bm->totedge == 0) {
- return OPERATOR_CANCELLED;
+ {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(eval_ctx.view_layer, &objects_len);
+ bool has_edges = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ ED_view3d_viewcontext_init_object(&vc, ob_iter);
+ if (vc.em->bm->totedge) {
+ has_edges = true;
+ }
+ }
+ MEM_SAFE_FREE(objects);
+ if (has_edges == false) {
+ return OPERATOR_CANCELLED;
+ }
}
vc.mval[0] = event->mval[0];
vc.mval[1] = event->mval[1];
/* return warning! */
- if (unified_findnearest(&eval_ctx, &vc, &eve, &eed, &efa) == 0) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ if (unified_findnearest(&eval_ctx, &vc, &basact, &eve, &eed, &efa) == 0) {
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data);
return OPERATOR_CANCELLED;
}
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
#ifdef USE_LINKED_SELECT_DEFAULT_HACK
- int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
+ int delimit = select_linked_delimit_default_from_op(op, vc.scene->toolsettings->selectmode);
#else
int delimit = RNA_enum_get(op->ptr, "delimit");
#endif
@@ -2954,9 +3085,11 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
BM_mesh_elem_index_ensure(bm, ele->head.htype);
index = EDBM_elem_to_index_any(em, ele);
+ /* TODO(MULTI_EDIT), index doesn't know which object,
+ * index selections isn't very common. */
RNA_int_set(op->ptr, "index", index);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index bf70cc3fa7e..78d563c64e9 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -93,7 +93,14 @@
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
+ 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];
+
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cuts = RNA_int_get(op->ptr, "number_cuts");
float smooth = RNA_float_get(op->ptr, "smoothness");
@@ -116,6 +123,9 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
RNA_int_get(op->ptr, "seed"));
EDBM_update_generic(em, true, true);
+ }
+
+ MEM_SAFE_FREE(objects);
return OPERATOR_FINISHED;
}
@@ -367,16 +377,22 @@ enum {
MESH_DELETE_ONLY_FACE = 4,
};
-static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
+static void edbm_report_delete_info(ReportList *reports, const int totelem_old[3], const int totelem_new[3])
{
BKE_reportf(reports, RPT_INFO,
"Removed: %d vertices, %d edges, %d faces",
- totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
+ totelem_old[0] - totelem_new[0], totelem_old[1] - totelem_new[1], totelem_old[2] - totelem_new[2]);
}
static int edbm_delete_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
+ 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];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int type = RNA_enum_get(op->ptr, "type");
@@ -412,6 +428,8 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
EDBM_update_generic(em, true, true);
+ } /* objects */
+
return OPERATOR_FINISHED;
}
@@ -467,17 +485,25 @@ static bool bm_face_is_loose(BMFace *f)
static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int totelem_old_sel[3];
+ int totelem_old[3];
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+
+ EDBM_mesh_stats_multi(objects, objects_len, totelem_old, totelem_old_sel);
- const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && bm->totvertsel);
- const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && bm->totedgesel);
- const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && bm->totfacesel);
+ const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && totelem_old_sel[0]);
+ const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && totelem_old_sel[1]);
+ const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && totelem_old_sel[2]);
- const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
@@ -520,8 +546,14 @@ static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
EDBM_update_generic(em, true, true);
+ }
+
+ int totelem_new[3];
+ EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL);
- edbm_report_delete_info(op->reports, bm, totelem);
+ edbm_report_delete_info(op->reports, totelem_old, totelem_new);
+
+ MEM_SAFE_FREE(objects);
return OPERATOR_FINISHED;
}
@@ -4096,11 +4128,18 @@ void MESH_OT_poke(wmOperatorType *ot)
static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
const int quad_method = RNA_enum_get(op->ptr, "quad_method");
const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
+ 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];
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMOperator bmop;
BMOIter oiter;
BMFace *f;
@@ -4117,11 +4156,15 @@ static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
EDBM_selectmode_flush(em);
+ // XXX, TODO
+#if 0
if (!EDBM_op_finish(em, &bmop, op, true)) {
return OPERATOR_CANCELLED;
}
+#endif
EDBM_update_generic(em, true, true);
+ }
return OPERATOR_FINISHED;
}
@@ -4155,7 +4198,22 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
+ 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);
+
+ bool is_face_pair;
+
+ {
+ int totelem_sel[3];
+ EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel);
+ is_face_pair = (totelem_sel[2] == 2);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
float angle_face_threshold, angle_shape_threshold;
@@ -4164,7 +4222,7 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
/* When joining exactly 2 faces, no limit.
* this is useful for one off joins while editing. */
prop = RNA_struct_find_property(op->ptr, "face_threshold");
- if ((em->bm->totfacesel == 2) &&
+ if (is_face_pair &&
(RNA_property_is_set(op->ptr, prop) == false))
{
angle_face_threshold = DEG2RADF(180.0f);
@@ -4174,7 +4232,7 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
}
prop = RNA_struct_find_property(op->ptr, "shape_threshold");
- if ((em->bm->totfacesel == 2) &&
+ if (is_face_pair &&
(RNA_property_is_set(op->ptr, prop) == false))
{
angle_shape_threshold = DEG2RADF(180.0f);
@@ -4197,10 +4255,11 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
do_seam, do_sharp, do_uvs, do_vcols, do_materials))
{
- return OPERATOR_CANCELLED;
+ continue;
}
EDBM_update_generic(em, true, true);
+ }
return OPERATOR_FINISHED;
}
@@ -4727,11 +4786,28 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int totelem_old[3] = {0, 0, 0};
+ int totelem_new[3] = {0, 0, 0};
+
+ 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];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ totelem_old[0] += bm->totvert;
+ totelem_old[1] += bm->totedge;
+ totelem_old[2] += bm->totface;
+ } /* objects */
+
const float thresh = RNA_float_get(op->ptr, "threshold");
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
- const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
if (!EDBM_op_callf(
em, op,
@@ -4746,7 +4822,12 @@ static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
EDBM_update_generic(em, true, true);
- edbm_report_delete_info(op->reports, bm, totelem);
+ totelem_new[0] += bm->totvert;
+ totelem_new[1] += bm->totedge;
+ totelem_new[2] += bm->totface;
+ }
+
+ edbm_report_delete_info(op->reports, totelem_old, totelem_new);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index ab7e13117a0..4d4b7a098b0 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -24,9 +24,12 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_key_types.h"
+#include "DNA_layer_types.h"
#include "BLI_listbase.h"
#include "BLI_array_utils.h"
@@ -35,6 +38,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
#include "BKE_undo_system.h"
@@ -44,6 +48,7 @@
#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_util.h"
+#include "ED_undo.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -69,6 +74,9 @@
# include "BLI_task.h"
#endif
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.mesh"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -668,16 +676,21 @@ static Object *editmesh_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
+typedef struct MeshUndoStep_Elem {
+ struct MeshUndoStep_Elem *next, *prev;
+ UndoRefID_Object obedit_ref;
+ UndoMesh data;
+} MeshUndoStep_Elem;
+
typedef struct MeshUndoStep {
UndoStep step;
- /* Use for all ID lookups (can be NULL). */
struct UndoIDPtrMap *id_map;
-
- /* note: will split out into list for multi-object-editmode. */
- UndoRefID_Object obedit_ref;
- UndoMesh data;
+ MeshUndoStep_Elem *elems;
+ uint elems_len;
} MeshUndoStep;
static bool mesh_undosys_poll(bContext *C)
@@ -688,10 +701,24 @@ static bool mesh_undosys_poll(bContext *C)
static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
MeshUndoStep *us = (MeshUndoStep *)us_p;
- us->obedit_ref.ptr = editmesh_object_from_context(C);
- Mesh *me = us->obedit_ref.ptr->data;
- undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key);
- 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];
+ MeshUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ Mesh *me = elem->obedit_ref.ptr->data;
+ undomesh_from_editmesh(&elem->data, me->edit_btmesh, me->key);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -702,18 +729,37 @@ static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNU
BLI_assert(mesh_undosys_poll(C));
MeshUndoStep *us = (MeshUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- Mesh *me = obedit->data;
- BMEditMesh *em = me->edit_btmesh;
- undomesh_to_editmesh(&us->data, em, obedit->data);
- DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MeshUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ Mesh *me = obedit->data;
+ if (me->edit_btmesh == 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;
+ }
+ BMEditMesh *em = me->edit_btmesh;
+ undomesh_to_editmesh(&elem->data, em, obedit->data);
+ 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 mesh_undosys_step_free(UndoStep *us_p)
{
MeshUndoStep *us = (MeshUndoStep *)us_p;
- undomesh_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MeshUndoStep_Elem *elem = &us->elems[i];
+ undomesh_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
if (us->id_map != NULL) {
BKE_undosys_ID_map_destroy(us->id_map);
@@ -724,7 +770,12 @@ static void mesh_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
MeshUndoStep *us = (MeshUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MeshUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
+
if (us->id_map != NULL) {
BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
}
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 531a26a66a8..dec13273417 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -60,6 +60,7 @@
#include "BKE_report.h"
#include "BKE_editmesh.h"
#include "BKE_multires.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -1297,3 +1298,47 @@ MDeformVert *ED_mesh_active_dvert_get_only(Object *ob)
return NULL;
}
}
+
+void EDBM_mesh_stats_multi(
+ struct Object **objects, const uint objects_len,
+ int totelem[3], int totelem_sel[3])
+{
+ if (totelem) {
+ totelem[0] = 0;
+ totelem[1] = 0;
+ totelem[2] = 0;
+ }
+ if (totelem_sel) {
+ totelem_sel[0] = 0;
+ totelem_sel[1] = 0;
+ totelem_sel[2] = 0;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ if (totelem) {
+ totelem[0] += bm->totvert;
+ totelem[1] += bm->totedge;
+ totelem[2] += bm->totface;
+ }
+ if (totelem_sel) {
+ totelem_sel[0] += bm->totvertsel;
+ totelem_sel[1] += bm->totedgesel;
+ totelem_sel[2] += bm->totfacesel;
+ }
+ }
+}
+
+
+void EDBM_mesh_elem_index_ensure_multi(Object **objects, const uint objects_len, const char htype)
+{
+ int elem_offset[4] = {0, 0, 0, 0};
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BM_mesh_elem_index_ensure_ex(bm, htype, elem_offset);
+ }
+}
diff --git a/source/blender/editors/metaball/CMakeLists.txt b/source/blender/editors/metaball/CMakeLists.txt
index 73f80774716..b0ae3122727 100644
--- a/source/blender/editors/metaball/CMakeLists.txt
+++ b/source/blender/editors/metaball/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index cc461c0c365..7045025e227 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -27,6 +27,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_array_utils.h"
@@ -36,17 +38,22 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
#include "DEG_depsgraph.h"
#include "ED_object.h"
#include "ED_mball.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.mball"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -130,13 +137,19 @@ static Object *editmball_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct MBallUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct MBallUndoStep_Elem {
UndoRefID_Object obedit_ref;
UndoMBall data;
+} MBallUndoStep_Elem;
+
+typedef struct MBallUndoStep {
+ UndoStep step;
+ MBallUndoStep_Elem *elems;
+ uint elems_len;
} MBallUndoStep;
static bool mball_undosys_poll(bContext *C)
@@ -147,36 +160,74 @@ static bool mball_undosys_poll(bContext *C)
static bool mball_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
MBallUndoStep *us = (MBallUndoStep *)us_p;
- us->obedit_ref.ptr = editmball_object_from_context(C);
- MetaBall *mb = us->obedit_ref.ptr->data;
- editmball_from_undomball(&us->data, mb);
- 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];
+ MBallUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ MetaBall *mb = ob->data;
+ editmball_from_undomball(&elem->data, mb);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
static void mball_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
ED_object_mode_set(C, OB_MODE_EDIT);
+ BLI_assert(mball_undosys_poll(C));
MBallUndoStep *us = (MBallUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- MetaBall *mb = obedit->data;
- undomball_to_editmball(&us->data, mb);
- DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MBallUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ MetaBall *mb = obedit->data;
+ if (mb->editelems == 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;
+ }
+ undomball_to_editmball(&elem->data, mb);
+ 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 mball_undosys_step_free(UndoStep *us_p)
{
MBallUndoStep *us = (MBallUndoStep *)us_p;
- undomball_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MBallUndoStep_Elem *elem = &us->elems[i];
+ undomball_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void mball_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
MBallUndoStep *us = (MBallUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MBallUndoStep_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/object/object_edit.c b/source/blender/editors/object/object_edit.c
index f4066360805..a17b1c122ad 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -89,6 +89,7 @@
#include "BKE_report.h"
#include "BKE_object.h"
#include "BKE_workspace.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -277,9 +278,6 @@ bool ED_object_editmode_load(Object *obedit)
void ED_object_editmode_exit_ex(bContext *C, Scene *scene, Object *obedit, int flag)
{
BLI_assert(C || !(flag & EM_DO_UNDO));
- /* Note! only in exceptional cases should 'EM_DO_UNDO' NOT be in the flag */
- /* Note! if 'EM_FREEDATA' isn't in the flag, use ED_object_editmode_load directly */
- ViewLayer *view_layer = CTX_data_view_layer(C);
const bool freedata = (flag & EM_FREEDATA) != 0;
if (flag & EM_WAITCURSOR) waitcursor(1);
@@ -287,8 +285,8 @@ void ED_object_editmode_exit_ex(bContext *C, Scene *scene, Object *obedit, int f
if (ED_object_editmode_load_ex(G.main, obedit, freedata) == false) {
/* in rare cases (background mode) its possible active object
* is flagged for editmode, without 'obedit' being set [#35489] */
- if (UNLIKELY(view_layer->basact && (view_layer->basact->object->mode & OB_MODE_EDIT))) {
- view_layer->basact->object->mode &= ~OB_MODE_EDIT;
+ if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) {
+ obedit->mode &= ~OB_MODE_EDIT;
}
if (flag & EM_WAITCURSOR) waitcursor(0);
return;
@@ -315,15 +313,18 @@ void ED_object_editmode_exit_ex(bContext *C, Scene *scene, Object *obedit, int f
if (flag & EM_DO_UNDO)
ED_undo_push(C, "Editmode");
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
+ if (C != NULL) {
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
+ }
+ else {
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
+ }
+
obedit->mode &= ~OB_MODE_EDIT;
}
if (flag & EM_WAITCURSOR) waitcursor(0);
-
- /* This way we ensure scene's obedit is copied into all CoW scenes. */
- DEG_id_tag_update(&scene->id, 0);
}
void ED_object_editmode_exit(bContext *C, int flag)
@@ -333,25 +334,12 @@ void ED_object_editmode_exit(bContext *C, int flag)
ED_object_editmode_exit_ex(C, scene, obedit, flag);
}
-void ED_object_editmode_enter(bContext *C, int flag)
+void ED_object_editmode_enter_ex(Scene *scene, Object *ob, int flag)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob;
bool ok = false;
- if (ID_IS_LINKED(scene)) return;
-
- if ((flag & EM_IGNORE_LAYER) == 0) {
- ob = CTX_data_active_object(C); /* active layer checked here for view3d */
-
- if (ob == NULL) return;
- }
- else {
- ob = view_layer->basact->object;
- }
-
if (ELEM(NULL, ob, ob->data)) return;
+ if (ID_IS_LINKED(ob)) return;
/* this checks actual object->data, for cases when other scenes have it in editmode context */
if (BKE_object_is_in_editmode(ob))
@@ -366,11 +354,6 @@ void ED_object_editmode_enter(bContext *C, int flag)
ob->restore_mode = ob->mode;
- /* note, when switching scenes the object can have editmode data but
- * not be scene->obedit: bug 22954, this avoids calling self eternally */
- if ((ob->restore_mode & OB_MODE_EDIT) == 0)
- ED_object_mode_toggle(C, ob->mode);
-
ob->mode = OB_MODE_EDIT;
if (ob->type == OB_MESH) {
@@ -387,7 +370,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
BKE_editmesh_tessface_calc(em);
}
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MESH, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL);
}
else if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
@@ -409,45 +392,64 @@ void ED_object_editmode_enter(bContext *C, int flag)
/* to ensure all goes in restposition and without striding */
DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* XXX: should this be OB_RECALC_DATA? */
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene);
}
else if (ob->type == OB_FONT) {
ok = 1;
ED_curve_editfont_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene);
}
else if (ob->type == OB_MBALL) {
ok = 1;
ED_mball_editmball_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene);
}
else if (ob->type == OB_LATTICE) {
ok = 1;
BKE_editlattice_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene);
}
else if (ob->type == OB_SURF || ob->type == OB_CURVE) {
ok = 1;
ED_curve_editnurb_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene);
}
if (ok) {
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- /* This way we ensure scene's obedit is copied into all CoW scenes. */
- DEG_id_tag_update(&scene->id, 0);
}
else {
- ob->mode &= ~OB_MODE_EDIT;
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
+ if ((flag & EM_NO_CONTEXT) == 0) {
+ ob->mode &= ~OB_MODE_EDIT;
+ }
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
}
- if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode");
if (flag & EM_WAITCURSOR) waitcursor(0);
+ BLI_assert((flag & EM_DO_UNDO) == 0);
+}
+
+void ED_object_editmode_enter(bContext *C, int flag)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob;
+
+ if ((flag & EM_IGNORE_LAYER) == 0) {
+ ob = CTX_data_active_object(C); /* active layer checked here for view3d */
+ }
+ else {
+ ob = view_layer->basact->object;
+ }
+ if (ob == NULL) return;
+ if (ID_IS_LINKED(ob)) return;
+
+ ED_object_editmode_enter_ex(scene, ob, flag & ~EM_DO_UNDO);
+ if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode");
}
static int editmode_toggle_exec(bContext *C, wmOperator *op)
@@ -455,18 +457,43 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
const int mode_flag = OB_MODE_EDIT;
const bool is_mode_set = (CTX_data_edit_object(C) != NULL);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
if (!is_mode_set) {
- Object *ob = CTX_data_active_object(C);
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
- if (!is_mode_set)
+ if (!is_mode_set) {
ED_object_editmode_enter(C, EM_WAITCURSOR);
- else
+ if (obact->mode & mode_flag) {
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob)
+ {
+ if ((ob != obact) && (ob->type == obact->type)) {
+ if (ob->flag & SELECT) {
+ ED_object_editmode_enter_ex(scene, ob, EM_WAITCURSOR | EM_NO_CONTEXT);
+ }
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
+ }
+ }
+ else {
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */
+ if ((obact->mode & mode_flag) == 0) {
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob)
+ {
+ if ((ob != obact) && (ob->type == obact->type)) {
+ if (ob->flag & SELECT) {
+ ED_object_editmode_exit_ex(NULL, scene, ob, EM_FREEDATA | EM_WAITCURSOR);
+ }
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
+ }
+ }
ED_space_image_uv_sculpt_update(CTX_wm_manager(C), scene);
@@ -510,27 +537,60 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
static int posemode_exec(bContext *C, wmOperator *op)
{
Base *base = CTX_data_active_base(C);
- Object *ob = base->object;
+ Object *obact = base->object;
const int mode_flag = OB_MODE_POSE;
- bool is_mode_set = (ob->mode & mode_flag) != 0;
+ bool is_mode_set = (obact->mode & mode_flag) != 0;
if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
- if (ob->type == OB_ARMATURE) {
- if (ob == CTX_data_edit_object(C)) {
+ if (obact->type == OB_ARMATURE) {
+ if (obact == CTX_data_edit_object(C)) {
ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
is_mode_set = false;
}
if (is_mode_set) {
- ED_object_posemode_exit(C, ob);
+ bool ok = ED_object_posemode_exit(C, obact);
+ if (ok) {
+ struct Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob)
+ {
+ if ((ob != obact) &&
+ (ob->type == OB_ARMATURE) &&
+ (ob->mode & mode_flag))
+ {
+ if (ob->flag & SELECT) {
+ ED_object_posemode_exit_ex(bmain, ob);
+ }
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
+ }
}
else {
- ED_object_posemode_enter(C, ob);
+ bool ok = ED_object_posemode_enter(C, obact);
+ if (ok) {
+ struct Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob)
+ {
+ if ((ob != obact) &&
+ (ob->type == OB_ARMATURE) &&
+ (ob->mode == OB_MODE_OBJECT) &&
+ (!ID_IS_LINKED(ob)))
+ {
+ if (ob->flag & SELECT) {
+ ED_object_posemode_enter_ex(bmain, ob);
+ }
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
+ }
}
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index f074a56fb86..f61e597e69e 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -177,6 +177,9 @@ bool ED_object_mode_generic_enter(
struct bContext *C, eObjectMode object_mode)
{
Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return (object_mode == OB_MODE_OBJECT);
+ }
if (ob->mode == object_mode) {
return true;
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 343e615f76b..c023c5d90bc 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
#include "DNA_gpencil_types.h"
@@ -42,7 +44,6 @@
#include "BLI_utildefines.h"
-
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_action.h"
@@ -209,6 +210,12 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
const bool editable_bones = CTX_data_equals(member, "editable_bones");
if (arm && arm->edbo) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ arm = ob->data;
+
/* Attention: X-Axis Mirroring is also handled here... */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
/* first and foremost, bone must be visible and selected */
@@ -241,6 +248,9 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
}
+ }
+ MEM_freeN(objects);
+
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
@@ -251,6 +261,12 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
const bool selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
if (arm && arm->edbo) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ arm = ob->data;
+
/* Attention: X-Axis Mirroring is also handled here... */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
/* first and foremost, bone must be visible and selected */
@@ -283,6 +299,9 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
}
+ }
+ MEM_freeN(objects);
+
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
@@ -293,12 +312,24 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bPoseChannel *pchan;
if (obpose && obpose->pose && arm) {
- for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
+ if (obpose != obact) {
+ for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
+ }
}
}
+ else if (obact->mode & OB_MODE_POSE) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, obact->mode, ob_iter) {
+ for (pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
+ }
+ }
+ } FOREACH_OBJECT_IN_MODE_END;
+ }
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
@@ -309,13 +340,28 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bPoseChannel *pchan;
if (obpose && obpose->pose && arm) {
- for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED)
- CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
+ if (obpose != obact) {
+ /* TODO(de-duplicate!) */
+ for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
+ }
}
}
+ else if (obact->mode & OB_MODE_POSE) {
+ /* TODO(de-duplicate!) */
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter) {
+ for (pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
+ }
+ }
+ } FOREACH_OBJECT_IN_MODE_END;
+ }
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 9fb602c81d6..744553dedb7 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -918,6 +918,7 @@ static void view3d_main_region_listener(
ob_data = OBEDIT_FROM_VIEW_LAYER(view_layer)->data;
}
if (ob_data) {
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(ob_data->name)));
/* TODO(sergey): Notifiers shouldn't really be doing DEG tags. */
DEG_id_tag_update(ob_data, DEG_TAG_SELECT_UPDATE);
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 6833dac558d..cdbcc3664a7 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -47,6 +47,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array.h"
#include "BLI_math.h"
#include "BLI_lasso_2d.h"
#include "BLI_rect.h"
@@ -126,6 +127,21 @@ void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
vc->obedit = CTX_data_edit_object(C);
}
+void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
+{
+ vc->obact = obact;
+ if (vc->obedit) {
+ BLI_assert(BKE_object_is_in_editmode(obact));
+ vc->obedit = obact;
+ /* previous selections are now invalid. */
+ vc->v3d->flag |= V3D_INVALID_BACKBUF;
+
+ if (vc->em) {
+ vc->em = BKE_editmesh_from_object(vc->obedit);
+ }
+ }
+}
+
/* ********************** view3d_select: selection manipulations ********************* */
/* local prototypes */
@@ -398,6 +414,7 @@ static void do_lasso_select_objects(
ViewContext *vc, const int mcords[][2], const short moves,
const bool extend, const bool select)
{
+ bool is_pose_mode = vc->obact ? (vc->obact->mode & OB_MODE_POSE) : false;
Base *base;
if (extend == false && select)
@@ -411,7 +428,10 @@ static void do_lasso_select_objects(
ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
}
}
- if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) {
+ if (is_pose_mode &&
+ ((vc->obact == base->object) || (base->flag & BASE_SELECTED)) &&
+ (base->object->mode & OB_MODE_POSE))
+ {
do_lasso_select_pose(vc, base->object, mcords, moves, select);
}
}
@@ -838,6 +858,10 @@ static void view3d_lasso_select(
}
}
else { /* Edit Mode */
+
+ FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, ob->mode, ob_iter) {
+ ED_view3d_viewcontext_init_object(vc, ob_iter);
+
switch (vc->obedit->type) {
case OB_MESH:
do_lasso_select_mesh(&eval_ctx, vc, mcords, moves, extend, select);
@@ -861,6 +885,8 @@ static void view3d_lasso_select(
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
}
@@ -1385,7 +1411,10 @@ static bool ed_object_select_pick(
/* signal for view3d_opengl_select to skip editmode objects */
vc.obedit = NULL;
}
-
+
+ /* In pose mode we don't want to mess with object selection. */
+ const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE);
+
/* always start list from basact in wire mode */
startbase = FIRSTBASE(view_layer);
if (BASACT(view_layer) && BASACT(view_layer)->next) startbase = BASACT(view_layer)->next;
@@ -1504,7 +1533,9 @@ static bool ed_object_select_pick(
}
}
}
- else if (ED_armature_pose_select_pick_with_buffer(view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest)) {
+ else if (ED_armature_pose_select_pick_with_buffer(
+ view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest))
+ {
/* then bone is found */
/* we make the armature selected:
@@ -1561,8 +1592,11 @@ static bool ed_object_select_pick(
}
}
else {
- deselectall_except(view_layer, basact);
- ED_object_base_select(basact, BA_SELECT);
+ /* When enabled, this puts other objects out of multi pose-mode. */
+ if (is_pose_mode == false) {
+ deselectall_except(view_layer, basact);
+ ED_object_base_select(basact, BA_SELECT);
+ }
}
if ((oldbasact != basact) && (is_obedit == false)) {
@@ -1907,20 +1941,28 @@ static int do_armature_box_select(
const struct EvaluationContext *eval_ctx, ViewContext *vc,
const rcti *rect, bool select, bool extend)
{
- bArmature *arm = vc->obedit->data;
int a;
unsigned int buffer[MAXPICKBUF];
int hits;
hits = view3d_opengl_select(eval_ctx, vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
-
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(eval_ctx->view_layer, &objects_len);
+
/* clear flag we use to detect point was affected */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next)
- ebone->flag &= ~BONE_DONE;
-
- if (extend == false && select)
- ED_armature_edit_deselect_all_visible(vc->obedit);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ if (extend == false && select) {
+ ED_armature_edit_deselect_all_visible_multi(objects, objects_len);
+ }
/* first we only check points inside the border */
for (a = 0; a < hits; a++) {
@@ -1929,7 +1971,9 @@ static int do_armature_box_select(
if ((index & 0xFFFF0000) == 0) {
continue;
}
- EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
+
+ EditBone *ebone;
+ ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone);
if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
if (index & BONESEL_TIP) {
ebone->flag |= BONE_DONE;
@@ -1947,10 +1991,14 @@ static int do_armature_box_select(
}
/* now we have to flush tag from parents... */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- if (ebone->parent->flag & BONE_DONE) {
- ebone->flag |= BONE_DONE;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if (ebone->parent->flag & BONE_DONE) {
+ ebone->flag |= BONE_DONE;
+ }
}
}
}
@@ -1960,7 +2008,8 @@ static int do_armature_box_select(
int index = buffer[(4 * a) + 3];
if (index != -1) {
if (index & BONESEL_BONE) {
- EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
+ EditBone *ebone;
+ ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone);
if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
if (!(ebone->flag & BONE_DONE)) {
if (select) {
@@ -1974,9 +2023,15 @@ static int do_armature_box_select(
}
}
}
-
- ED_armature_edit_sync_selection(arm->edbo);
-
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ ED_armature_edit_sync_selection(arm->edbo);
+ }
+
+ MEM_freeN(objects);
+
return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
@@ -2009,31 +2064,31 @@ static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_
static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend)
{
EvaluationContext eval_ctx;
- Bone *bone;
- Object *ob = vc->obact;
unsigned int *vbuffer = NULL; /* selection buffer */
- unsigned int *col; /* color in buffer */
int bone_only;
- int bone_selected = 0;
int totobj = MAXPICKBUF; /* XXX solve later */
int hits;
CTX_data_eval_ctx(C, &eval_ctx);
- if ((ob) && (ob->mode & OB_MODE_POSE))
+ if (vc->obact && (vc->obact->mode & OB_MODE_POSE))
bone_only = 1;
else
bone_only = 0;
if (extend == false && select) {
if (bone_only) {
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) {
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, OB_MODE_POSE, ob_iter) {
+ bArmature *arm = ob_iter->data;
+ for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) {
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
}
}
- CTX_DATA_END;
+ FOREACH_OBJECT_IN_MODE_END;
}
else {
object_deselect_all_visible(vc->view_layer);
@@ -2053,60 +2108,77 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
*/
if (hits > 0) { /* no need to loop if there's no hit */
- Base *base;
- col = vbuffer + 3;
/* The draw order doesn't always match the order we populate the engine, see: T51695. */
qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
- /*
- * Even though 'DRW_draw_select_loop' uses 'DEG_OBJECT_ITER_BEGIN',
- * we can be sure the order remains the same between both.
- */
- for (base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
+ Base **bases = NULL;
+ BLI_array_declare(bases);
+
+ for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
if (BASE_SELECTABLE(base)) {
- while (base->object->select_color == (*col & 0xFFFF)) { /* we got an object */
- if (*col & 0xFFFF0000) { /* we got a bone */
- bone = ED_armature_bone_find_index(base->object, *col & ~(BONESEL_ANY));
- if (bone) {
- if (select) {
- if ((bone->flag & BONE_UNSELECTABLE) == 0) {
- bone->flag |= BONE_SELECTED;
- bone_selected = 1;
- }
- }
- else {
- bArmature *arm = base->object->data;
- bone->flag &= ~BONE_SELECTED;
- if (arm->act_bone == bone)
- arm->act_bone = NULL;
- }
+ if ((base->object->select_color & 0x0000FFFF) != 0) {
+ BLI_array_append(bases, base);
+ }
+ }
+ }
+
+ for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
+ Bone *bone;
+ Base *base = ED_armature_base_and_bone_from_select_buffer(bases, BLI_array_len(bases), *col, &bone);
+
+ if (base == NULL) {
+ continue;
+ }
+ /* Loop over contiguous bone hits for 'base'. */
+ bool bone_selected = false;
+ for (; col != col_end; col += 4) {
+ /* should never fail */
+ if (bone != NULL) {
+ if (select) {
+ if ((bone->flag & BONE_UNSELECTABLE) == 0) {
+ bone->flag |= BONE_SELECTED;
+ bone_selected = true;
}
}
- else if (!bone_only) {
- ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
+ else {
+ bArmature *arm = base->object->data;
+ bone->flag &= ~BONE_SELECTED;
+ if (arm->act_bone == bone)
+ arm->act_bone = NULL;
}
-
- col += 4; /* next color */
- hits--;
- if (hits == 0) break;
+ }
+ else if (!bone_only) {
+ ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
+ }
+
+ /* Select the next bone if we're not switching bases. */
+ if (col + 4 != col_end) {
+ if ((base->object->select_color & 0x0000FFFF) != (col[4] & 0x0000FFFF)) {
+ break;
+ }
+ const uint hit_bone = (col[4] & ~BONESEL_ANY) >> 16;
+ bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);;
+ bone = pchan ? pchan->bone : NULL;
}
}
-
+
if (bone_selected) {
if (base->object && (base->object->type == OB_ARMATURE)) {
bArmature *arm = base->object->data;
-
+
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
-
- if (arm && (arm->flag & ARM_HAS_VIZ_DEPS)) {
+
+ if (vc->obact && arm && (arm->flag & ARM_HAS_VIZ_DEPS)) {
/* mask modifier ('armature' mode), etc. */
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&vc->obact->id, OB_RECALC_DATA);
}
}
}
}
-
+
+ MEM_freeN(bases);
+
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
}
MEM_freeN(vbuffer);
@@ -2135,36 +2207,39 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rcti(op, &rect);
if (vc.obedit) {
+
+ FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, vc.obedit->mode, ob_iter) {
+ ED_view3d_viewcontext_init_object(&vc, ob_iter);
+
switch (vc.obedit->type) {
case OB_MESH:
vc.em = BKE_editmesh_from_object(vc.obedit);
- ret = do_mesh_box_select(&eval_ctx, &vc, &rect, select, extend);
-// if (EM_texFaceCheck())
+ ret |= do_mesh_box_select(&eval_ctx, &vc, &rect, select, extend);
if (ret & OPERATOR_FINISHED) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
break;
case OB_CURVE:
case OB_SURF:
- ret = do_nurbs_box_select(&vc, &rect, select, extend);
+ ret |= do_nurbs_box_select(&vc, &rect, select, extend);
if (ret & OPERATOR_FINISHED) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
break;
case OB_MBALL:
- ret = do_meta_box_select(&eval_ctx, &vc, &rect, select, extend);
+ ret |= do_meta_box_select(&eval_ctx, &vc, &rect, select, extend);
if (ret & OPERATOR_FINISHED) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
break;
case OB_ARMATURE:
- ret = do_armature_box_select(&eval_ctx, &vc, &rect, select, extend);
+ ret |= do_armature_box_select(&eval_ctx, &vc, &rect, select, extend);
if (ret & OPERATOR_FINISHED) {
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
}
break;
case OB_LATTICE:
- ret = do_lattice_box_select(&vc, &rect, select, extend);
+ ret |= do_lattice_box_select(&vc, &rect, select, extend);
if (ret & OPERATOR_FINISHED) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
@@ -2173,25 +2248,34 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
assert(!"border select on incorrect object type");
break;
}
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
else { /* no editmode, unified for bones and objects */
if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
- ret = ED_sculpt_mask_box_select(C, &vc, &rect, select, extend);
+ ret |= ED_sculpt_mask_box_select(C, &vc, &rect, select, extend);
}
else if (vc.obact && BKE_paint_select_face_test(vc.obact)) {
- ret = do_paintface_box_select(&eval_ctx, &vc, &rect, select, extend);
+ ret |= do_paintface_box_select(&eval_ctx, &vc, &rect, select, extend);
}
else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) {
- ret = do_paintvert_box_select(&eval_ctx, &vc, &rect, select, extend);
+ ret |= do_paintvert_box_select(&eval_ctx, &vc, &rect, select, extend);
}
else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
- ret = PE_border_select(C, &rect, select, extend);
+ ret |= PE_border_select(C, &rect, select, extend);
}
else { /* object mode with none active */
- ret = do_object_pose_box_select(C, &vc, &rect, select, extend);
+ ret |= do_object_pose_box_select(C, &vc, &rect, select, extend);
}
}
+ if (ret & OPERATOR_FINISHED) {
+ ret = OPERATOR_FINISHED;
+ }
+ else {
+ ret = OPERATOR_CANCELLED;
+ }
+
return ret;
}
@@ -2832,23 +2916,30 @@ static bool object_circle_select(ViewContext *vc, const bool select, const int m
/* not a real operator, only for circle test */
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- Object *obact = CTX_data_active_object(C);
+ ViewContext vc;
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
const int radius = RNA_int_get(op->ptr, "radius");
const bool select = !RNA_boolean_get(op->ptr, "deselect");
const int mval[2] = {RNA_int_get(op->ptr, "x"),
RNA_int_get(op->ptr, "y")};
- if (CTX_data_edit_object(C) || BKE_paint_select_elem_test(obact) ||
+
+ ED_view3d_viewcontext_init(C, &vc);
+
+ Object *obact = vc.obact;
+ Object *obedit = vc.obedit;
+
+ if (obedit || BKE_paint_select_elem_test(obact) ||
(obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) )
{
- EvaluationContext eval_ctx;
- ViewContext vc;
-
view3d_operator_needs_opengl(C);
-
- CTX_data_eval_ctx(C, &eval_ctx);
- ED_view3d_viewcontext_init(C, &vc);
+
+ FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, obact->mode, ob_iter) {
+ ED_view3d_viewcontext_init_object(&vc, ob_iter);
+
+ obact = vc.obact;
+ obedit = vc.obedit;
if (CTX_data_edit_object(C)) {
obedit_circle_select(&eval_ctx, &vc, select, mval, (float)radius);
@@ -2862,20 +2953,21 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
paint_vertsel_circle_select(&eval_ctx, &vc, select, mval, (float)radius);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
}
- else if (obact->mode & OB_MODE_POSE)
+ else if (obact->mode & OB_MODE_POSE) {
pose_circle_select(&vc, select, mval, (float)radius);
- else
+ }
+ else {
return PE_circle_select(C, select, mval, (float)radius);
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
else if (obact && obact->mode & OB_MODE_SCULPT) {
return OPERATOR_CANCELLED;
}
else {
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
-
if (object_circle_select(&vc, select, mval, (float)radius)) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
}
}
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index d4c5f6053b4..8c4aeb1d136 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -110,7 +110,7 @@ static void drawEdgeSlide(TransInfo *t);
static void drawVertSlide(TransInfo *t);
static void postInputRotation(TransInfo *t, float values[3]);
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around);
+static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around);
static void initSnapSpatial(TransInfo *t, float r_snap[3]);
@@ -211,7 +211,8 @@ static bool transdata_check_local_center(TransInfo *t, short around)
{
return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
(t->flag & (T_OBJECT | T_POSE)) ||
- (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
+ /* implicit: (t->flag & T_EDIT) */
+ (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
(t->spacetype == SPACE_IPO) ||
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))
);
@@ -220,7 +221,7 @@ static bool transdata_check_local_center(TransInfo *t, short around)
bool transdata_check_local_islands(TransInfo *t, short around)
{
return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
- (t->obedit && ELEM(t->obedit->type, OB_MESH))));
+ (ELEM(t->obedit_type, OB_MESH))));
}
/* ************************** SPACE DEPENDANT CODE **************************** */
@@ -245,6 +246,7 @@ void setTransformViewMatrices(TransInfo *t)
}
calculateCenter2D(t);
+ calculateCenterLocal(t, t->center_global);
}
void setTransformViewAspect(TransInfo *t, float r_aspect[3])
@@ -619,8 +621,12 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
else {
// XXX how to deal with lock?
SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
- if (sima->lock) WM_event_add_notifier(C, NC_GEOM | ND_DATA, t->obedit->data);
- else ED_area_tag_redraw(t->sa);
+ if (sima->lock) {
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
+ }
+ else {
+ ED_area_tag_redraw(t->sa);
+ }
}
}
else if (t->spacetype == SPACE_CLIP) {
@@ -1024,7 +1030,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
else {
- if (t->obedit && t->obedit->type == OB_MESH) {
+ if (t->obedit_type == OB_MESH) {
if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
restoreTransObjects(t);
resetTransModal(t);
@@ -1570,7 +1576,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
t->around = centerMode; // override userdefined mode
- if (t->total == 0) {
+ if (t->data_len_all == 0) {
success = false;
}
else {
@@ -1971,7 +1977,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->proportional_fcurve = proportional;
else if (t->spacetype == SPACE_ACTION)
ts->proportional_action = proportional;
- else if (t->obedit)
+ else if (t->obedit_type != -1)
ts->proportional = proportional;
else if (t->options & CTX_MASK)
ts->proportional_mask = (proportional != PROP_EDIT_OFF);
@@ -2161,7 +2167,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
createTransData(C, t); // make TransData structs from selection
- if (t->total == 0) {
+ if (t->data_len_all == 0) {
postTrans(C, t);
return 0;
}
@@ -2265,7 +2271,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
break;
case TFM_BONESIZE:
{ /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
- bArmature *arm = t->poseobj->data;
+ /* Note: we have to pick one, use the active object. */
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+ bArmature *arm = tc->poseobj->data;
if (arm->drawtype == ARM_ENVELOPE) {
initBoneEnvelope(t);
t->mode = TFM_BONE_ENVELOPE_DIST;
@@ -2870,6 +2878,7 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
* \{ */
struct BendCustomData {
+ /* All values are in global space. */
float warp_sta[3];
float warp_end[3];
@@ -2910,9 +2919,9 @@ static void initBend(TransInfo *t)
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- calculateCenterCursor(t, t->center);
+ calculateCenterCursor(t, t->center_global);
}
- calculateCenterGlobal(t, t->center, t->center_global);
+ calculateCenterLocal(t, t->center_global);
t->val = 0.0f;
@@ -2923,10 +2932,6 @@ static void initBend(TransInfo *t)
ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end);
copy_v3_v3(data->warp_nor, t->viewinv[2]);
- if (t->flag & T_EDIT) {
- sub_v3_v3(data->warp_sta, t->obedit->obmat[3]);
- sub_v3_v3(data->warp_end, t->obedit->obmat[3]);
- }
normalize_v3(data->warp_nor);
/* tangent */
@@ -2953,10 +2958,9 @@ static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
static void Bend(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float vec[3];
- float pivot[3];
- float warp_end_radius[3];
+ float pivot_global[3];
+ float warp_end_radius_global[3];
int i;
char str[UI_MAX_DRAW_STR];
const struct BendCustomData *data = t->custom.mode.data;
@@ -3011,20 +3015,42 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
values.scale *= data->warp_init_dist;
/* calc 'data->warp_end' from 'data->warp_end_init' */
- copy_v3_v3(warp_end_radius, data->warp_end);
- dist_ensure_v3_v3fl(warp_end_radius, data->warp_sta, values.scale);
+ copy_v3_v3(warp_end_radius_global, data->warp_end);
+ dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale);
/* done */
/* calculate pivot */
- copy_v3_v3(pivot, data->warp_sta);
+ copy_v3_v3(pivot_global, data->warp_sta);
if (values.angle > 0.0f) {
- madd_v3_v3fl(pivot, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
+ madd_v3_v3fl(pivot_global, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
+ }
+ else {
+ madd_v3_v3fl(pivot_global, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
+ }
+
+ /* TODO(campbell): xform, compensate object center. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+
+ float warp_sta_local[3];
+ float warp_end_local[3];
+ float warp_end_radius_local[3];
+ float pivot_local[3];
+
+ if (t->flag & T_EDIT) {
+ sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->obedit->obmat[3]);
+ sub_v3_v3v3(warp_end_local, data->warp_end, tc->obedit->obmat[3]);
+ sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->obedit->obmat[3]);
+ sub_v3_v3v3(pivot_local, pivot_global, tc->obedit->obmat[3]);
}
else {
- madd_v3_v3fl(pivot, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
+ copy_v3_v3(warp_sta_local, data->warp_sta);
+ copy_v3_v3(warp_end_local, data->warp_end);
+ copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
+ copy_v3_v3(pivot_local, pivot_global);
}
- for (i = 0; i < t->total; i++, td++) {
+ for (i = 0; i < tc->data_len; i++, td++) {
float mat[3][3];
float delta[3];
float fac, fac_scaled;
@@ -3043,34 +3069,35 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
copy_v3_v3(vec, td->iloc);
mul_m3_v3(td->mtx, vec);
- fac = line_point_factor_v3(vec, data->warp_sta, warp_end_radius);
+ fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
if (is_clamp) {
CLAMP(fac, 0.0f, 1.0f);
}
fac_scaled = fac * td->factor;
axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
- interp_v3_v3v3(delta, data->warp_sta, warp_end_radius, fac_scaled);
- sub_v3_v3(delta, data->warp_sta);
+ interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
+ sub_v3_v3(delta, warp_sta_local);
/* delta is subtracted, rotation adds back this offset */
sub_v3_v3(vec, delta);
- sub_v3_v3(vec, pivot);
+ sub_v3_v3(vec, pivot_local);
mul_m3_v3(mat, vec);
- add_v3_v3(vec, pivot);
+ add_v3_v3(vec, pivot_local);
mul_m3_v3(td->smtx, vec);
/* rotation */
if ((t->flag & T_POINTS) == 0) {
- ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
+ ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS);
}
/* location */
copy_v3_v3(td->loc, vec);
}
-
+ }
+
recalcData(t);
ED_area_headerprint(t->sa, str);
@@ -3141,7 +3168,6 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float vec[3];
float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
float value;
@@ -3184,7 +3210,9 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
mul_m3_m3m3(tmat, smat, persmat);
mul_m3_m3m3(totmat, persinv, tmat);
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
const float *center, *co;
if (td->flag & TD_NOACTION)
@@ -3192,8 +3220,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
if (td->flag & TD_SKIP)
continue;
-
- if (t->obedit) {
+
+ if (t->flag & T_EDIT) {
float mat3[3][3];
mul_m3_m3m3(mat3, totmat, td->mtx);
mul_m3_m3m3(tmat, td->smtx, mat3);
@@ -3207,7 +3235,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
co = td->loc;
}
else {
- center = t->center;
+ center = tc->center_local;
co = td->center;
}
@@ -3222,7 +3250,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3v3(td->loc, td->iloc, vec);
}
-
+ }
+
recalcData(t);
ED_area_headerprint(t->sa, str);
@@ -3248,7 +3277,7 @@ static void initResize(TransInfo *t)
t->num.val_flag[1] |= NUM_NULL_ONE;
t->num.val_flag[2] |= NUM_NULL_ONE;
t->num.flag |= NUM_AFFECT_ALL;
- if (!t->obedit) {
+ if ((t->flag & T_EDIT) == 0) {
t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
@@ -3332,7 +3361,7 @@ static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
if (dot_v3v3(rmat[2], smat[2]) < 0.0f) size[2] = -size[2];
}
-static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
+static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
{
float tmat[3][3], smat[3][3], center[3];
float vec[3];
@@ -3346,7 +3375,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
}
if (t->con.applySize) {
- t->con.applySize(t, td, tmat);
+ t->con.applySize(t, tc, td, tmat);
}
/* local constraint shouldn't alter center */
@@ -3358,11 +3387,11 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
copy_v3_v3(center, td->center);
}
else {
- copy_v3_v3(center, t->center);
+ copy_v3_v3(center, tc->center_local);
}
}
else {
- copy_v3_v3(center, t->center);
+ copy_v3_v3(center, tc->center_local);
}
if (td->ext) {
@@ -3435,7 +3464,6 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float mat[3][3];
int i;
char str[UI_MAX_DRAW_STR];
@@ -3460,32 +3488,38 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
size_to_mat3(mat, t->values);
if (t->con.applySize) {
- t->con.applySize(t, NULL, mat);
+ t->con.applySize(t, NULL, NULL, mat);
}
copy_m3_m3(t->mat, mat); // used in manipulator
headerResize(t, t->values, str);
-
- for (i = 0, td = t->data; i < t->total; i++, td++) {
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
-
- ElementResize(t, td, mat);
+
+ ElementResize(t, tc, td, mat);
}
-
+ }
+
/* evil hack - redo resize if cliping needed */
if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 1)) {
size_to_mat3(mat, t->values);
-
+
if (t->con.applySize)
- t->con.applySize(t, NULL, mat);
-
- for (i = 0, td = t->data; i < t->total; i++, td++)
- ElementResize(t, td, mat);
+ t->con.applySize(t, NULL, NULL, mat);
+
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++)
+ ElementResize(t, tc, td, mat);
/* In proportional edit it can happen that */
/* vertices in the radius of the brush end */
@@ -3494,6 +3528,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
if (t->flag & T_PROP_EDIT_ALL) {
clipUVData(t);
}
+ }
}
recalcData(t);
@@ -3521,7 +3556,7 @@ static void initSkinResize(TransInfo *t)
t->num.val_flag[1] |= NUM_NULL_ONE;
t->num.val_flag[2] |= NUM_NULL_ONE;
t->num.flag |= NUM_AFFECT_ALL;
- if (!t->obedit) {
+ if ((t->flag & T_EDIT) == 0) {
t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
@@ -3545,7 +3580,6 @@ static void initSkinResize(TransInfo *t)
static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float size[3], mat[3][3];
int i;
char str[UI_MAX_DRAW_STR];
@@ -3569,8 +3603,10 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
size_to_mat3(mat, size);
headerResize(t, size, str);
-
- for (i = 0, td = t->data; i < t->total; i++, td++) {
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
float tmat[3][3], smat[3][3];
float fsize[3];
@@ -3589,14 +3625,15 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
}
if (t->con.applySize) {
- t->con.applySize(t, NULL, tmat);
+ t->con.applySize(t, NULL, NULL, tmat);
}
mat3_to_size(fsize, tmat);
td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
}
-
+ }
+
recalcData(t);
ED_area_headerprint(t->sa, str);
@@ -3612,7 +3649,6 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
static void initToSphere(TransInfo *t)
{
- TransData *td = t->data;
int i;
t->mode = TFM_TOSPHERE;
@@ -3632,13 +3668,16 @@ static void initToSphere(TransInfo *t)
t->num.val_flag[0] |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
t->flag |= T_NO_CONSTRAINT;
-
+
// Calculate average radius
- for (i = 0; i < t->total; i++, td++) {
- t->val += len_v3v3(t->center, td->iloc);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ t->val += len_v3v3(tc->center_local, td->iloc);
}
-
- t->val /= (float)t->total;
+ }
+
+ t->val /= (float)t->data_len_all;
}
static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
@@ -3647,8 +3686,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
float ratio, radius;
int i;
char str[UI_MAX_DRAW_STR];
- TransData *td = t->data;
-
+
ratio = t->values[0];
snapGridIncrement(t, &ratio);
@@ -3671,28 +3709,29 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
/* default header print */
BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
}
-
-
- for (i = 0; i < t->total; i++, td++) {
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
float tratio;
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
-
- sub_v3_v3v3(vec, td->iloc, t->center);
-
+
+ sub_v3_v3v3(vec, td->iloc, tc->center_local);
+
radius = normalize_v3(vec);
tratio = ratio * td->factor;
mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
-
- add_v3_v3v3(td->loc, t->center, vec);
+
+ add_v3_v3v3(td->loc, tc->center_local, vec);
}
-
-
+ }
+
recalcData(t);
ED_area_headerprint(t->sa, str);
@@ -3709,7 +3748,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
static void postInputRotation(TransInfo *t, float values[3])
{
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
- t->con.applyRot(t, NULL, t->axis, values);
+ t->con.applyRot(t, NULL, NULL, t->axis, values);
}
}
@@ -3754,7 +3793,7 @@ static void initRotation(TransInfo *t)
*
* Protected axis and other transform settings are taken into account.
*/
-static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center)
+static void ElementRotation_ex(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const float *center)
{
float vec[3], totmat[3][3], smat[3][3];
float eul[3], fmat[3][3], quat[4];
@@ -3801,7 +3840,7 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
float pmtx[3][3], imtx[3][3];
// Extract and invert armature object matrix
- copy_m3_m4(pmtx, t->poseobj->obmat);
+ copy_m3_m4(pmtx, tc->poseobj->obmat);
invert_m3_m3(imtx, pmtx);
if ((td->flag & TD_NO_LOC) == 0) {
@@ -3967,7 +4006,7 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
}
}
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around)
+static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around)
{
const float *center;
@@ -3976,22 +4015,23 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const
center = td->center;
}
else {
- center = t->center;
+ center = tc->center_local;
}
- ElementRotation_ex(t, td, mat, center);
+ ElementRotation_ex(t, tc, td, mat, center);
}
static void applyRotationValue(TransInfo *t, float angle, float axis[3])
{
- TransData *td = t->data;
float mat[3][3];
int i;
axis_angle_normalized_to_mat3(mat, axis, angle);
-
- for (i = 0; i < t->total; i++, td++) {
-
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+
if (td->flag & TD_NOACTION)
break;
@@ -3999,14 +4039,15 @@ static void applyRotationValue(TransInfo *t, float angle, float axis[3])
continue;
if (t->con.applyRot) {
- t->con.applyRot(t, td, axis, NULL);
+ t->con.applyRot(t, tc, td, axis, NULL);
axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
}
else if (t->flag & T_PROP_EDIT) {
axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
}
-
- ElementRotation(t, td, mat, t->around);
+
+ ElementRotation(t, tc, td, mat, t->around);
+ }
}
}
@@ -4022,7 +4063,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
snapGridIncrement(t, &final);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
- t->con.applyRot(t, NULL, t->axis, NULL);
+ t->con.applyRot(t, NULL, NULL, t->axis, NULL);
}
else {
/* reset axis if constraint is not set */
@@ -4091,7 +4132,6 @@ static void initTrackball(TransInfo *t)
static void applyTrackballValue(TransInfo *t, const float axis1[3], const float axis2[3], float angles[2])
{
- TransData *td = t->data;
float mat[3][3];
float axis[3];
float angle;
@@ -4102,7 +4142,9 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
angle = normalize_v3(axis);
axis_angle_normalized_to_mat3(mat, axis, angle);
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4113,7 +4155,8 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
}
- ElementRotation(t, td, mat, t->around);
+ ElementRotation(t, tc, td, mat, t->around);
+ }
}
}
@@ -4368,24 +4411,26 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
static void applyTranslationValue(TransInfo *t, const float vec[3])
{
- TransData *td = t->data;
+ const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
float tvec[3];
/* The ideal would be "apply_snap_align_rotation" only when a snap point is found
* so, maybe inside this function is not the best place to apply this rotation.
* but you need "handle snapping rotation before doing the translation" (really?) */
- const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
float pivot[3];
if (apply_snap_align_rotation) {
copy_v3_v3(pivot, t->tsnap.snapTarget);
/* The pivot has to be in local-space (see T49494) */
if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
+ Object *ob = tc->obedit ? tc->obedit : tc->poseobj;
mul_m4_v3(ob->imat, pivot);
}
}
- for (int i = 0; i < t->total; i++, td++) {
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4414,7 +4459,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
unit_m3(mat);
}
- ElementRotation_ex(t, td, mat, pivot);
+ ElementRotation_ex(t, tc, td, mat, pivot);
if (td->loc) {
use_rotate_offset = true;
@@ -4424,7 +4469,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
if (t->con.applyVec) {
float pvec[3];
- t->con.applyVec(t, td, vec, tvec, pvec);
+ t->con.applyVec(t, tc, td, vec, tvec, pvec);
}
else {
copy_v3_v3(tvec, vec);
@@ -4444,6 +4489,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
constraintTransLim(t, td);
}
+ }
}
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
@@ -4468,7 +4514,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
- t->con.applyVec(t, NULL, t->values, value_final, pvec);
+ t->con.applyVec(t, NULL, NULL, t->values, value_final, pvec);
headerTranslation(t, pvec, str);
/* only so we have re-usable value with redo, see T46741. */
@@ -4512,7 +4558,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
static void initShrinkFatten(TransInfo *t)
{
// If not in mesh edit mode, fallback to Resize
- if (t->obedit == NULL || t->obedit->type != OB_MESH) {
+ if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) {
initResize(t);
}
else {
@@ -4542,7 +4588,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
- TransData *td = t->data;
distance = -t->values[0];
@@ -4579,7 +4624,9 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
/* done with header string */
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
float tdistance; /* temp dist */
if (td->flag & TD_NOACTION)
break;
@@ -4595,6 +4642,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
}
+ }
recalcData(t);
@@ -4633,7 +4681,6 @@ static void initTilt(TransInfo *t)
static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4661,7 +4708,9 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4672,6 +4721,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
*td->val = td->ival + final * td->factor;
}
}
+ }
recalcData(t);
@@ -4713,7 +4763,6 @@ static void initCurveShrinkFatten(TransInfo *t)
static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float ratio;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4737,7 +4786,9 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4751,6 +4802,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (*td->val <= 0.0f) *td->val = 0.001f;
}
}
+ }
recalcData(t);
@@ -4792,7 +4844,6 @@ static void initMaskShrinkFatten(TransInfo *t)
static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float ratio;
int i;
bool initial_feather = false;
@@ -4821,7 +4872,9 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (ratio > 1.0f) {
initial_feather = true;
- for (td = t->data, i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4831,10 +4884,13 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (td->ival >= 0.001f)
initial_feather = false;
}
+ }
}
/* apply shrink/fatten */
- for (td = t->data, i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4852,6 +4908,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (*td->val <= 0.0f) *td->val = 0.001f;
}
}
+ }
recalcData(t);
@@ -4893,7 +4950,6 @@ static void initGPShrinkFatten(TransInfo *t)
static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float ratio;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4917,7 +4973,9 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4931,6 +4989,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (*td->val <= 0.0f) *td->val = 0.001f;
}
}
+ }
recalcData(t);
@@ -4970,7 +5029,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
float distance;
int i;
char str[UI_MAX_DRAW_STR];
- TransData *td = t->data;
distance = t->values[0];
@@ -4994,21 +5052,23 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
}
if (t->con.applyRot && t->con.mode & CON_APPLY) {
- t->con.applyRot(t, NULL, axis_global, NULL);
+ t->con.applyRot(t, NULL, NULL, axis_global, NULL);
}
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
- sub_v3_v3v3(vec, t->center, td->center);
+ sub_v3_v3v3(vec, tc->center_local, td->center);
if (t->con.applyRot && t->con.mode & CON_APPLY) {
float axis[3];
copy_v3_v3(axis, axis_global);
- t->con.applyRot(t, td, axis, NULL);
+ t->con.applyRot(t, tc, td, axis, NULL);
mul_m3_v3(td->smtx, axis);
if (isLockConstraint(t)) {
@@ -5024,6 +5084,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3v3(td->loc, td->iloc, vec);
}
+ }
recalcData(t);
@@ -5060,7 +5121,6 @@ static void initBevelWeight(TransInfo *t)
static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float weight;
int i;
char str[UI_MAX_DRAW_STR];
@@ -5094,7 +5154,9 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -5104,6 +5166,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
if (*td->val > 1.0f) *td->val = 1.0f;
}
}
+ }
recalcData(t);
@@ -5140,7 +5203,6 @@ static void initCrease(TransInfo *t)
static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float crease;
int i;
char str[UI_MAX_DRAW_STR];
@@ -5174,7 +5236,9 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Crease: %.3f %s"), crease, t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -5187,6 +5251,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
if (*td->val > 1.0f) *td->val = 1.0f;
}
}
+ }
recalcData(t);
@@ -5251,7 +5316,7 @@ static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRA
}
}
-static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
+static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
{
float tmat[3][3], smat[3][3], oldy;
float sizemat[3][3];
@@ -5260,7 +5325,7 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
mul_m3_m3m3(tmat, td->smtx, smat);
if (t->con.applySize) {
- t->con.applySize(t, td, tmat);
+ t->con.applySize(t, tc, td, tmat);
}
/* we've tucked the scale in loc */
@@ -5273,7 +5338,6 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float size[3], mat[3][3];
float ratio = t->values[0];
int i;
@@ -5292,23 +5356,26 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
size_to_mat3(mat, size);
if (t->con.applySize) {
- t->con.applySize(t, NULL, mat);
+ t->con.applySize(t, NULL, NULL, mat);
}
copy_m3_m3(t->mat, mat); // used in manipulator
headerBoneSize(t, size, str);
-
- for (i = 0; i < t->total; i++, td++) {
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
-
- ElementBoneSize(t, td, mat);
+
+ ElementBoneSize(t, tc, td, mat);
}
-
+ }
+
recalcData(t);
ED_area_headerprint(t->sa, str);
@@ -5344,7 +5411,6 @@ static void initBoneEnvelope(TransInfo *t)
static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float ratio;
int i;
char str[UI_MAX_DRAW_STR];
@@ -5367,8 +5433,10 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
else {
BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %3f"), ratio);
}
-
- for (i = 0; i < t->total; i++, td++) {
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -5383,7 +5451,8 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
*td->val = ratio;
}
}
-
+ }
+
recalcData(t);
ED_area_headerprint(t->sa, str);
@@ -5397,9 +5466,9 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
* \{ */
static void slide_origdata_init_flag(
- TransInfo *t, SlideOrigData *sod)
+ TransInfo *t, TransDataContainer *tc, SlideOrigData *sod)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
const bool has_layer_math = CustomData_has_math(&bm->ldata);
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -5420,10 +5489,10 @@ static void slide_origdata_init_flag(
}
static void slide_origdata_init_data(
- TransInfo *t, SlideOrigData *sod)
+ TransDataContainer *tc, SlideOrigData *sod)
{
if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
sod->origfaces = BLI_ghash_ptr_new(__func__);
@@ -5484,11 +5553,11 @@ static void slide_origdata_create_data_vert(
}
static void slide_origdata_create_data(
- TransInfo *t, SlideOrigData *sod,
+ TransInfo *t, TransDataContainer *tc, SlideOrigData *sod,
TransDataGenericSlideVert *sv_array, unsigned int v_stride, unsigned int v_num)
{
if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
unsigned int i;
TransDataGenericSlideVert *sv;
@@ -5520,15 +5589,15 @@ static void slide_origdata_create_data(
}
if (t->flag & T_MIRROR) {
- TransData *td = t->data;
+ TransData *td = tc->data;
TransDataGenericSlideVert *sv_mirror;
- sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * t->total, __func__);
- sod->totsv_mirror = t->total;
+ sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * tc->data_len, __func__);
+ sod->totsv_mirror = tc->data_len;
sv_mirror = sod->sv_mirror;
- for (i = 0; i < t->total; i++, td++) {
+ for (i = 0; i < tc->data_len; i++, td++) {
BMVert *eve = td->extra;
if (eve) {
sv_mirror->v = eve;
@@ -5682,12 +5751,12 @@ static void slide_origdata_interp_data_vert(
}
static void slide_origdata_interp_data(
- TransInfo *t, SlideOrigData *sod,
+ Object *obedit, SlideOrigData *sod,
TransDataGenericSlideVert *sv, unsigned int v_stride, unsigned int v_num,
bool is_final)
{
if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
unsigned int i;
const bool has_mdisps = (sod->cd_loop_mdisp_offset != -1);
@@ -5750,7 +5819,7 @@ static void slide_origdata_free_date(
static void calcEdgeSlideCustomPoints(struct TransInfo *t)
{
- EdgeSlideData *sld = t->custom.mode.data;
+ EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
@@ -5947,11 +6016,11 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
* Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
*/
static void calcEdgeSlide_mval_range(
- TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
+ TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
const float mval[2], const bool use_occlude_geometry, const bool use_calc_direction)
{
TransDataEdgeSlideVert *sv_array = sld->sv;
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
ARegion *ar = t->ar;
View3D *v3d = NULL;
@@ -5978,7 +6047,7 @@ static void calcEdgeSlide_mval_range(
unit_m4(projectMat);
}
else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
}
if (use_occlude_geometry) {
@@ -6021,7 +6090,7 @@ static void calcEdgeSlide_mval_range(
/* This test is only relevant if object is not wire-drawn! See [#32068]. */
if (use_occlude_geometry &&
- !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, t->obedit))
+ !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, tc->obedit))
{
continue;
}
@@ -6109,7 +6178,7 @@ static void calcEdgeSlide_mval_range(
}
static void calcEdgeSlide_even(
- TransInfo *t, EdgeSlideData *sld, const float mval[2])
+ TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const float mval[2])
{
TransDataEdgeSlideVert *sv = sld->sv;
@@ -6134,7 +6203,7 @@ static void calcEdgeSlide_even(
unit_m4(projectMat);
}
else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
}
for (i = 0; i < sld->totsv; i++, sv++) {
@@ -6154,9 +6223,9 @@ static void calcEdgeSlide_even(
}
}
-static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
BMIter iter;
BMEdge *e;
@@ -6171,13 +6240,9 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
- slide_origdata_init_flag(t, &sld->orig_data);
+ slide_origdata_init_flag(t, tc, &sld->orig_data);
- sld->use_even = use_even;
sld->curr_sv_index = 0;
- sld->flipped = flipped;
- if (!use_clamp)
- t->flag |= T_ALT_TRANSFORM;
/*ensure valid selection*/
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -6493,26 +6558,24 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
if (t->spacetype == SPACE_VIEW3D) {
v3d = t->sa ? t->sa->spacedata.first : NULL;
rv3d = t->ar ? t->ar->regiondata : NULL;
- use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
+ calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
/* create copies of faces for customdata projection */
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_init_data(tc, &sld->orig_data);
+ slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
if (rv3d) {
- calcEdgeSlide_even(t, sld, mval);
+ calcEdgeSlide_even(t, tc, sld, mval);
}
sld->em = em;
-
- sld->perc = 0.0f;
-
- t->custom.mode.data = sld;
-
+
+ tc->custom.mode.data = sld;
+
MEM_freeN(sv_table);
return true;
@@ -6522,9 +6585,9 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
* A simple version of #createEdgeSlideVerts_double_side
* Which assumes the longest unselected.
*/
-static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
BMIter iter;
BMEdge *e;
@@ -6544,15 +6607,9 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
rv3d = t->ar ? t->ar->regiondata : NULL;
}
- slide_origdata_init_flag(t, &sld->orig_data);
+ slide_origdata_init_flag(t, tc, &sld->orig_data);
- sld->use_even = use_even;
sld->curr_sv_index = 0;
- /* happens to be best for single-sided */
- sld->flipped = !flipped;
- if (!use_clamp)
- t->flag |= T_ALT_TRANSFORM;
-
/* ensure valid selection */
{
int i = 0, j = 0;
@@ -6696,25 +6753,23 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
if (t->spacetype == SPACE_VIEW3D) {
v3d = t->sa ? t->sa->spacedata.first : NULL;
rv3d = t->ar ? t->ar->regiondata : NULL;
- use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
+ calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
/* create copies of faces for customdata projection */
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_init_data(tc, &sld->orig_data);
+ slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
if (rv3d) {
- calcEdgeSlide_even(t, sld, mval);
+ calcEdgeSlide_even(t, tc, sld, mval);
}
sld->em = em;
- sld->perc = 0.0f;
-
- t->custom.mode.data = sld;
+ tc->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -6723,14 +6778,16 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
void projectEdgeSlideData(TransInfo *t, bool is_final)
{
- EdgeSlideData *sld = t->custom.mode.data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
SlideOrigData *sod = &sld->orig_data;
if (sod->use_origfaces == false) {
return;
}
- slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+ slide_origdata_interp_data(tc->obedit, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+ }
}
void freeEdgeSlideTempFaces(EdgeSlideData *sld)
@@ -6738,7 +6795,7 @@ void freeEdgeSlideTempFaces(EdgeSlideData *sld)
slide_origdata_free_date(&sld->orig_data);
}
-void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
+void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
{
EdgeSlideData *sld = custom_data->data;
@@ -6758,30 +6815,53 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
{
EdgeSlideData *sld;
- bool ok;
+ bool ok = false;
t->mode = TFM_EDGE_SLIDE;
t->transform = applyEdgeSlide;
t->handleEvent = handleEventEdgeSlide;
+ {
+ EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+ slp->use_even = use_even;
+ slp->flipped = flipped;
+ /* happens to be best for single-sided */
+ if (use_double_side == false) {
+ slp->flipped = !flipped;
+ }
+ slp->perc = 0.0f;
+
+ if (!use_clamp) {
+ t->flag |= T_ALT_TRANSFORM;
+ }
+
+ t->custom.mode.data = slp;
+ t->custom.mode.use_free = true;
+ }
+
if (use_double_side) {
- ok = createEdgeSlideVerts_double_side(t, use_even, flipped, use_clamp);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createEdgeSlideVerts_double_side(t, tc);
+ }
}
else {
- ok = createEdgeSlideVerts_single_side(t, use_even, flipped, use_clamp);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createEdgeSlideVerts_single_side(t, tc);
+ }
}
if (!ok) {
t->state = TRANS_CANCEL;
return;
}
-
- sld = t->custom.mode.data;
-
- if (!sld)
- return;
- t->custom.mode.free_cb = freeEdgeSlideVerts;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sld = tc->custom.mode.data;
+ if (!sld) {
+ continue;
+ }
+ tc->custom.mode.free_cb = freeEdgeSlideVerts;
+ }
/* set custom point first if you want value to be initialized by init */
calcEdgeSlideCustomPoints(t);
@@ -6808,20 +6888,20 @@ static void initEdgeSlide(TransInfo *t)
static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->custom.mode.data;
+ EdgeSlideParams *slp = t->custom.mode.data;
- if (sld) {
+ if (slp) {
switch (event->type) {
case EKEY:
if (event->val == KM_PRESS) {
- sld->use_even = !sld->use_even;
+ slp->use_even = !slp->use_even;
calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
case FKEY:
if (event->val == KM_PRESS) {
- sld->flipped = !sld->flipped;
+ slp->flipped = !slp->flipped;
calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
@@ -6835,6 +6915,7 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
}
break;
case EVT_MODAL_MAP:
+#if 0
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
@@ -6843,6 +6924,7 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
return TREDRAW_HARD;
}
+#endif
break;
case MOUSEMOVE:
calcEdgeSlideCustomPoints(t);
@@ -6857,12 +6939,13 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
static void drawEdgeSlide(TransInfo *t)
{
- if ((t->mode == TFM_EDGE_SLIDE) && t->custom.mode.data) {
- EdgeSlideData *sld = t->custom.mode.data;
+ if ((t->mode == TFM_EDGE_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
+ EdgeSlideParams *slp = t->custom.mode.data;
+ EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
/* Even mode */
- if ((sld->use_even == true) || (is_clamp == false)) {
+ if ((slp->use_even == true) || (is_clamp == false)) {
View3D *v3d = t->view;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
@@ -6873,16 +6956,16 @@ static void drawEdgeSlide(TransInfo *t)
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
gpuPushMatrix();
- gpuMultMatrix(t->obedit->obmat);
+ gpuMultMatrix(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- if (sld->use_even == true) {
+ if (slp->use_even == true) {
float co_a[3], co_b[3], co_mark[3];
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float fac = (sld->perc + 1.0f) / 2.0f;
+ const float fac = (slp->perc + 1.0f) / 2.0f;
const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
const float guide_size = ctrl_size - 0.5f;
const int alpha_shade = -30;
@@ -6906,7 +6989,7 @@ static void drawEdgeSlide(TransInfo *t)
immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
glPointSize(ctrl_size);
immBegin(GWN_PRIM_POINTS, 1);
- if (sld->flipped) {
+ if (slp->flipped) {
if (curr_sv->v_side[1]) immVertex3fv(pos, curr_sv->v_side[1]->co);
}
else {
@@ -6932,6 +7015,7 @@ static void drawEdgeSlide(TransInfo *t)
immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
immBegin(GWN_PRIM_LINES, sld->totsv * 2);
+ /* TODO(campbell): Loop over all verts */
sv = sld->sv;
for (i = 0; i < sld->totsv; i++, sv++) {
float a[3], b[3];
@@ -6972,28 +7056,32 @@ static void drawEdgeSlide(TransInfo *t)
static void doEdgeSlide(TransInfo *t, float perc)
{
- EdgeSlideData *sld = t->custom.mode.data;
- TransDataEdgeSlideVert *svlist = sld->sv, *sv;
- int i;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ EdgeSlideData *sld_active = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
- sld->perc = perc;
- sv = svlist;
+ slp->perc = perc;
- if (sld->use_even == false) {
+ if (slp->use_even == false) {
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
if (is_clamp) {
const int side_index = (perc < 0.0f);
const float perc_final = fabsf(perc);
- for (i = 0; i < sld->totsv; i++, sv++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
}
-
sld->curr_side_unclamp = side_index;
+ }
}
else {
- const int side_index = sld->curr_side_unclamp;
- const float perc_init = fabsf(perc) * ((sld->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
- for (i = 0; i < sld->totsv; i++, sv++) {
+ const float perc_init = fabsf(perc) * ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
+ const int side_index = sld_active->curr_side_unclamp;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
float dir_flip[3];
float perc_final = perc_init;
if (!is_zero_v3(sv->dir_side[side_index])) {
@@ -7005,6 +7093,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
}
madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
}
+ }
}
}
else {
@@ -7016,20 +7105,23 @@ static void doEdgeSlide(TransInfo *t, float perc)
* \note len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])
* is the same as the distance between the original vert locations, same goes for the lines below.
*/
- TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float curr_length_perc = curr_sv->edge_len * (((sld->flipped ? perc : -perc) + 1.0f) / 2.0f);
+ TransDataEdgeSlideVert *curr_sv = &sld_active->sv[sld_active->curr_sv_index];
+ const float curr_length_perc = curr_sv->edge_len * (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f);
float co_a[3];
float co_b[3];
- for (i = 0; i < sld->totsv; i++, sv++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
if (sv->edge_len > FLT_EPSILON) {
const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
- if (sld->flipped) {
+ if (slp->flipped) {
interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
}
else {
@@ -7037,6 +7129,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
}
}
}
+ }
}
}
@@ -7045,9 +7138,9 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
- EdgeSlideData *sld = t->custom.mode.data;
- bool flipped = sld->flipped;
- bool use_even = sld->use_even;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ bool flipped = slp->flipped;
+ bool use_even = slp->use_even;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
@@ -7099,7 +7192,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
static void calcVertSlideCustomPoints(struct TransInfo *t)
{
- VertSlideData *sld = t->custom.mode.data;
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
const float *co_orig_3d = sv->co_orig_3d;
@@ -7134,7 +7227,8 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
*/
static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
{
- VertSlideData *sld = t->custom.mode.data;
+ /* Active object may have no selected vertices. */
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
float mval_fl[2] = {UNPACK2(mval)};
TransDataVertSlideVert *sv;
@@ -7161,7 +7255,7 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
*/
static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
{
- VertSlideData *sld = t->custom.mode.data;
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
float imval_fl[2] = {UNPACK2(t->mouse.imval)};
float mval_fl[2] = {UNPACK2(mval)};
@@ -7189,7 +7283,7 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
float dir_dot;
sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
- mul_mat3_m4_v3(t->obedit->obmat, tdir);
+ mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir);
project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
normalize_v3(tdir);
@@ -7207,9 +7301,9 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
}
}
-static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
BMIter iter;
BMIter eiter;
@@ -7219,13 +7313,9 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
int j;
- slide_origdata_init_flag(t, &sld->orig_data);
+ slide_origdata_init_flag(t, tc, &sld->orig_data);
- sld->use_even = use_even;
sld->curr_sv_index = 0;
- sld->flipped = flipped;
- if (!use_clamp)
- t->flag |= T_ALT_TRANSFORM;
j = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -7288,14 +7378,12 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
sld->totsv = j;
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_init_data(tc, &sld->orig_data);
+ slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
sld->em = em;
- sld->perc = 0.0f;
-
- t->custom.mode.data = sld;
+ tc->custom.mode.data = sld;
/* most likely will be set below */
unit_m4(sld->proj_mat);
@@ -7307,9 +7395,12 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
rv3d = ar ? ar->regiondata : NULL;
if (rv3d) {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, sld->proj_mat);
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat);
}
+ }
+ /* XXX, calc vert slide across all objects */
+ if (tc == t->data_container) {
calcVertSlideMouseActiveVert(t, t->mval);
calcVertSlideMouseActiveEdges(t, t->mval);
}
@@ -7319,14 +7410,13 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
void projectVertSlideData(TransInfo *t, bool is_final)
{
- VertSlideData *sld = t->custom.mode.data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
SlideOrigData *sod = &sld->orig_data;
-
- if (sod->use_origfaces == false) {
- return;
+ if (sod->use_origfaces == true) {
+ slide_origdata_interp_data(tc->obedit, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+ }
}
-
- slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
}
void freeVertSlideTempFaces(VertSlideData *sld)
@@ -7334,7 +7424,7 @@ void freeVertSlideTempFaces(VertSlideData *sld)
slide_origdata_free_date(&sld->orig_data);
}
-void freeVertSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
+void freeVertSlideVerts(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
{
VertSlideData *sld = custom_data->data;
@@ -7361,23 +7451,38 @@ void freeVertSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
- VertSlideData *sld;
t->mode = TFM_VERT_SLIDE;
t->transform = applyVertSlide;
t->handleEvent = handleEventVertSlide;
- if (!createVertSlideVerts(t, use_even, flipped, use_clamp)) {
- t->state = TRANS_CANCEL;
- return;
+ {
+ VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+ slp->use_even = use_even;
+ slp->flipped = flipped;
+ slp->perc = 0.0f;
+
+ if (!use_clamp) {
+ t->flag |= T_ALT_TRANSFORM;
+ }
+
+ t->custom.mode.data = slp;
+ t->custom.mode.use_free = true;
}
- sld = t->custom.mode.data;
+ bool ok = false;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createVertSlideVerts(t, tc);
+ VertSlideData *sld = tc->custom.mode.data;
+ if (sld) {
+ tc->custom.mode.free_cb = freeVertSlideVerts;
+ }
+ }
- if (!sld)
+ if (ok == false) {
+ t->state = TRANS_CANCEL;
return;
-
- t->custom.mode.free_cb = freeVertSlideVerts;
+ }
/* set custom point first if you want value to be initialized by init */
calcVertSlideCustomPoints(t);
@@ -7404,14 +7509,14 @@ static void initVertSlide(TransInfo *t)
static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = t->custom.mode.data;
+ VertSlideParams *slp = t->custom.mode.data;
- if (sld) {
+ if (slp) {
switch (event->type) {
case EKEY:
if (event->val == KM_PRESS) {
- sld->use_even = !sld->use_even;
- if (sld->flipped) {
+ slp->use_even = !slp->use_even;
+ if (slp->flipped) {
calcVertSlideCustomPoints(t);
}
return TREDRAW_HARD;
@@ -7419,7 +7524,7 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
break;
case FKEY:
if (event->val == KM_PRESS) {
- sld->flipped = !sld->flipped;
+ slp->flipped = !slp->flipped;
calcVertSlideCustomPoints(t);
return TREDRAW_HARD;
}
@@ -7464,8 +7569,8 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
static void drawVertSlide(TransInfo *t)
{
- if ((t->mode == TFM_VERT_SLIDE) && t->custom.mode.data) {
- VertSlideData *sld = t->custom.mode.data;
+ if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
/* Non-Prop mode */
@@ -7485,12 +7590,12 @@ static void drawVertSlide(TransInfo *t)
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
gpuPushMatrix();
- gpuMultMatrix(t->obedit->obmat);
+ gpuMultMatrix(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
glLineWidth(line_size);
const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
-
+
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
@@ -7540,13 +7645,13 @@ static void drawVertSlide(TransInfo *t)
mval_ofs[0] = t->mval[0] - t->mouse.imval[0];
mval_ofs[1] = t->mval[1] - t->mouse.imval[1];
- mul_v3_m4v3(co_orig_3d, t->obedit->obmat, curr_sv->co_orig_3d);
+ mul_v3_m4v3(co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d);
zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL);
ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac);
- invert_m4_m4(t->obedit->imat, t->obedit->obmat);
- mul_mat3_m4_v3(t->obedit->imat, co_dest_3d);
+ invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
+ mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d);
add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
@@ -7581,7 +7686,8 @@ static void drawVertSlide(TransInfo *t)
static void doVertSlide(TransInfo *t, float perc)
{
- VertSlideData *sld = t->custom.mode.data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
TransDataVertSlideVert *svlist = sld->sv, *sv;
int i;
@@ -7618,6 +7724,7 @@ static void doVertSlide(TransInfo *t, float perc)
}
}
}
+ }
}
static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
@@ -7625,9 +7732,9 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
- VertSlideData *sld = t->custom.mode.data;
- const bool flipped = sld->flipped;
- const bool use_even = sld->use_even;
+ VertSlideData *slp = t->custom.mode.data;
+ const bool flipped = slp->flipped;
+ const bool use_even = slp->use_even;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
@@ -7700,7 +7807,6 @@ static void initBoneRoll(TransInfo *t)
static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
int i;
char str[UI_MAX_DRAW_STR];
@@ -7726,7 +7832,9 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
}
/* set roll values */
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -7735,6 +7843,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
*(td->val) = td->ival - final;
}
+ }
recalcData(t);
@@ -7767,7 +7876,6 @@ static void initBakeTime(TransInfo *t)
static void applyBakeTime(TransInfo *t, const int mval[2])
{
- TransData *td = t->data;
float time;
int i;
char str[UI_MAX_DRAW_STR];
@@ -7811,7 +7919,9 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
BLI_snprintf(str, sizeof(str), IFACE_("Time: %.3f %s"), time, t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -7824,6 +7934,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
}
}
+ }
recalcData(t);
@@ -7844,14 +7955,13 @@ static void initMirror(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_NONE);
t->flag |= T_NULL_ONE;
- if (!t->obedit) {
+ if ((t->flag & T_EDIT) == 0) {
t->flag |= T_NO_ZERO;
}
}
static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float size[3], mat[3][3];
int i;
char str[UI_MAX_DRAW_STR];
@@ -7869,19 +7979,22 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
size_to_mat3(mat, size);
if (t->con.applySize) {
- t->con.applySize(t, NULL, mat);
+ t->con.applySize(t, NULL, NULL, mat);
}
BLI_snprintf(str, sizeof(str), IFACE_("Mirror%s"), t->con.text);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
- ElementResize(t, td, mat);
+ ElementResize(t, tc, td, mat);
+ }
}
recalcData(t);
@@ -7893,14 +8006,17 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
size_to_mat3(mat, size);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
- ElementResize(t, td, mat);
+ ElementResize(t, tc, td, mat);
+ }
}
recalcData(t);
@@ -7931,14 +8047,15 @@ static void initAlign(TransInfo *t)
static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float center[3];
int i;
- /* saving original center */
- copy_v3_v3(center, t->center);
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ /* saving original center */
+ copy_v3_v3(center, tc->center_local);
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
float mat[3][3], invmat[3][3];
if (td->flag & TD_NOACTION)
@@ -7949,11 +8066,11 @@ static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
/* around local centers */
if (t->flag & (T_OBJECT | T_POSE)) {
- copy_v3_v3(t->center, td->center);
+ copy_v3_v3(tc->center_local, td->center);
}
else {
if (t->settings->selectmode & SCE_SELECT_FACE) {
- copy_v3_v3(t->center, td->center);
+ copy_v3_v3(tc->center_local, td->center);
}
}
@@ -7961,11 +8078,11 @@ static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
mul_m3_m3m3(mat, t->spacemtx, invmat);
- ElementRotation(t, td, mat, t->around);
+ ElementRotation(t, tc, td, mat, t->around);
}
-
/* restoring original center */
- copy_v3_v3(t->center, center);
+ copy_v3_v3(tc->center_local, center);
+ }
recalcData(t);
@@ -8027,10 +8144,11 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRA
static void applySeqSlideValue(TransInfo *t, const float val[2])
{
- TransData *td = t->data;
int i;
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -8039,6 +8157,7 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
}
+ }
}
static void applySeqSlide(TransInfo *t, const int mval[2])
@@ -8050,7 +8169,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
- t->con.applyVec(t, NULL, t->values, tvec, pvec);
+ t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
copy_v3_v3(t->values, tvec);
}
else {
@@ -8270,18 +8389,19 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
static void applyTimeTranslateValue(TransInfo *t)
{
- TransData *td = t->data;
- TransData2D *td2d = t->data2d;
Scene *scene = t->scene;
int i;
-
+
const short autosnap = getAnimEdit_SnapMode(t);
const double secf = FPS;
float deltax, val /* , valprev */;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ TransData2D *td2d = tc->data_2d;
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
- for (i = 0; i < t->total; i++, td++, td2d++) {
+ for (i = 0; i < tc->data_len; i++, td++, td2d++) {
/* it is assumed that td->extra is a pointer to the AnimData,
* whose active action is where this keyframe comes from
* (this is only valid when not in NLA)
@@ -8321,6 +8441,7 @@ static void applyTimeTranslateValue(TransInfo *t)
/* apply nearest snapping */
doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
}
+ }
}
static void applyTimeTranslate(TransInfo *t, const int mval[2])
@@ -8386,9 +8507,9 @@ static void initTimeSlide(TransInfo *t)
float min = 999999999.0f, max = -999999999.0f;
int i;
-
- TransData *td = t->data;
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
float val = *(td->val);
@@ -8399,6 +8520,7 @@ static void initTimeSlide(TransInfo *t)
if (min > val) min = val;
if (max < val) max = val;
}
+ }
if (min == max) {
/* just use the current frame ranges */
@@ -8450,7 +8572,6 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW
static void applyTimeSlideValue(TransInfo *t, float sval)
{
- TransData *td = t->data;
int i;
const float *range = t->custom.mode.data;
float minx = range[0];
@@ -8465,7 +8586,9 @@ static void applyTimeSlideValue(TransInfo *t, float sval)
}
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
/* it is assumed that td->extra is a pointer to the AnimData,
* whose active action is where this keyframe comes from
* (this is only valid when not in NLA)
@@ -8506,6 +8629,7 @@ static void applyTimeSlideValue(TransInfo *t, float sval)
}
}
}
+ }
}
static void applyTimeSlide(TransInfo *t, const int mval[2])
@@ -8563,8 +8687,8 @@ static void initTimeScale(TransInfo *t)
/* recalculate center2d to use CFRA and mouse Y, since that's
* what is used in time scale */
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- t->center[0] = t->scene->r.cfra;
- projectFloatView(t, t->center, center);
+ t->center_global[0] = t->scene->r.cfra;
+ projectFloatView(t, t->center_global, center);
center[1] = t->mouse.imval[1];
}
@@ -8605,15 +8729,15 @@ static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
static void applyTimeScaleValue(TransInfo *t)
{
Scene *scene = t->scene;
- TransData *td = t->data;
- TransData2D *td2d = t->data2d;
int i;
const short autosnap = getAnimEdit_SnapMode(t);
const double secf = FPS;
-
- for (i = 0; i < t->total; i++, td++, td2d++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ TransData2D *td2d = tc->data_2d;
+ for (i = 0; i < tc->data_len; i++, td++, td2d++) {
/* it is assumed that td->extra is a pointer to the AnimData,
* whose active action is where this keyframe comes from
* (this is only valid when not in NLA)
@@ -8639,6 +8763,7 @@ static void applyTimeScaleValue(TransInfo *t)
/* apply nearest snapping */
doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
}
+ }
}
static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
@@ -8666,7 +8791,7 @@ bool checkUseAxisMatrix(TransInfo *t)
/* currently only checks for editmode */
if (t->flag & T_EDIT) {
if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)))
+ (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)))
{
/* not all editmode supports axis-matrix */
return true;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index fe05207e645..ba496a0c744 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -47,6 +47,7 @@
struct Depsgraph;
struct TransInfo;
+struct TransDataContainer;
struct TransData;
struct TransformOrientation;
struct TransSnap;
@@ -109,7 +110,7 @@ typedef struct TransSnap {
* \note Return value can be anything,
* where the smallest absolute value defines whats closest.
*/
- float (*distance)(struct TransInfo *, const float p1[3], const float p2[3]);
+ float (*distance)(struct TransInfo *t, const float p1[3], const float p2[3]);
/**
* Re-usable snap context data.
@@ -127,14 +128,16 @@ typedef struct TransCon {
/* the one in TransInfo is not garanty to stay the same (Rotates change it) */
int mode; /* Mode flags of the Constraint */
void (*drawExtra)(struct TransInfo *t);
+
+ /* Note: if 'tc' is NULL, 'td' must also be NULL. */
/* For constraints that needs to draw differently from the other
* uses this instead of the generic draw function */
- void (*applyVec)(struct TransInfo *t, struct TransData *td, const float in[3], float out[3], float pvec[3]);
+ void (*applyVec)(struct TransInfo *t, struct TransDataContainer *tc, struct TransData *td, const float in[3], float out[3], float pvec[3]);
/* Apply function pointer for linear vectorial transformation */
/* The last three parameters are pointers to the in/out/printable vectors */
- void (*applySize)(struct TransInfo *t, struct TransData *td, float smat[3][3]);
+ void (*applySize)(struct TransInfo *t, struct TransDataContainer *tc, struct TransData *td, float smat[3][3]);
/* Apply function pointer for size transformation */
- void (*applyRot)(struct TransInfo *t, struct TransData *td, float vec[3], float *angle);
+ void (*applyRot)(struct TransInfo *t, struct TransDataContainer *tc, struct TransData *td, float vec[3], float *angle);
/* Apply function pointer for rotation transformation */
} TransCon;
@@ -270,10 +273,6 @@ typedef struct EdgeSlideData {
SlideOrigData orig_data;
- float perc;
-
- bool use_even;
- bool flipped;
int curr_sv_index;
@@ -281,6 +280,12 @@ typedef struct EdgeSlideData {
int curr_side_unclamp;
} EdgeSlideData;
+typedef struct EdgeSlideParams {
+ float perc;
+
+ bool use_even;
+ bool flipped;
+} EdgeSlideParams;
typedef struct TransDataVertSlideVert {
/* TransDataGenericSlideVert */
@@ -313,6 +318,13 @@ typedef struct VertSlideData {
float proj_mat[4][4];
} VertSlideData;
+typedef struct VertSlideParams {
+ float perc;
+
+ bool use_even;
+ bool flipped;
+} VertSlideParams;
+
typedef struct BoneInitData {
struct EditBone *bone;
float tail[3];
@@ -373,16 +385,68 @@ typedef struct MouseInput {
typedef struct TransCustomData {
void *data;
- void (*free_cb)(struct TransInfo *, struct TransCustomData *);
+ void (*free_cb)(struct TransInfo *, struct TransDataContainer *tc, struct TransCustomData *custom_data);
unsigned int use_free : 1;
} TransCustomData;
typedef struct TransCenterData {
- float local[3], global[3];
+ float global[3];
unsigned int is_set : 1;
} TransCenterData;
+/**
+ * Rule of thumb for choosing between mode/type:
+ * - If transform mode uses the data, assign to `mode`
+ * (typically in transform.c).
+ * - If conversion uses the data as an extension to the #TransData, assign to `type`
+ * (typically in transform_conversion.c).
+ */
+typedef struct TransCustomDataContainer {
+ /** Owned by the mode (grab, scale, bend... ).*/
+ union {
+ TransCustomData mode, first_elem;
+ };
+ TransCustomData type;
+} TransCustomDataContainer;
+#define TRANS_CUSTOM_DATA_ELEM_MAX (sizeof(TransCustomDataContainer) / sizeof(TransCustomData))
+
+typedef struct TransDataContainer {
+ /**
+ * Use for cases we care about the active, eg: active vert of active mesh.
+ * if set this will _always_ be the first item in the array.
+ */
+ bool is_active;
+
+ /** Transformed data (array). */
+ TransData *data;
+ /** Total number of transformed data. */
+ int data_len;
+
+ /** Transformed data extension (array). */
+ TransDataExtension *data_ext;
+ /** Transformed data for 2d (array). */
+ TransData2D *data_2d;
+
+ struct Object *obedit;
+ /** Normalized editmode matrix ('T_EDIT' only). */
+ float obedit_mat[3][3];
+
+ /** if 't->flag & T_POSE', this denotes pose object */
+ struct Object *poseobj;
+
+ /** Center of transformation (in local-space), Calculated from #TransInfo.center_global. */
+ float center_local[3];
+
+ TransCustomDataContainer custom;
+} TransDataContainer;
+
typedef struct TransInfo {
+ TransDataContainer *data_container;
+ int data_container_len;
+ /** Combine length of all #TransDataContainer.data_len
+ * Use to check if nothing is selected or if we have a single selection. */
+ int data_len_all;
+
int mode; /* current mode */
int flag; /* generic flags for special behaviors */
int modifiers; /* special modifiers, by function, not key */
@@ -393,10 +457,6 @@ typedef struct TransInfo {
/* transform function pointer */
eRedrawFlag (*handleEvent)(struct TransInfo *, const struct wmEvent *);
/* event handler function pointer RETURN 1 if redraw is needed */
- int total; /* total number of transformed data */
- TransData *data; /* transformed data (array) */
- TransDataExtension *ext; /* transformed data extension (array) */
- TransData2D *data2d; /* transformed data for 2d (array) */
TransCon con; /* transformed constraint */
TransSnap tsnap;
NumInput num; /* numerical input */
@@ -406,7 +466,6 @@ typedef struct TransInfo {
char proptext[20]; /* proportional falloff text */
float aspect[3]; /* spaces using non 1:1 aspect, (uv's, f-curve, movie-clip... etc)
* use for conversion and snapping. */
- float center[3]; /* center of transformation (in local-space) */
float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
/* Lazy initialize center data for when we need other center values.
@@ -425,6 +484,7 @@ typedef struct TransInfo {
short around;
char spacetype; /* spacetype where transforming is */
char helpline; /* helpline modes (not to be confused with hotline) */
+ short obedit_type; /* Avoid looking inside TransDataContainer obedit. */
float vec[3]; /* translation, to show for widget */
float mat[3][3]; /* rot/rescale, to show for widget */
@@ -432,25 +492,6 @@ typedef struct TransInfo {
float spacemtx[3][3]; /* orientation matrix of the current space */
char spacename[64]; /* name of the current space, MAX_NAME */
- struct Object *poseobj; /* if t->flag & T_POSE, this denotes pose object */
-
- /**
- * Rule of thumb for choosing between mode/type:
- * - If transform mode uses the data, assign to `mode`
- * (typically in transform.c).
- * - If conversion uses the data as an extension to the #TransData, assign to `type`
- * (typically in transform_conversion.c).
- */
- struct {
- /* owned by the mode (grab, scale, bend... )*/
- union {
- TransCustomData mode, first_elem;
- };
- /* owned by the type (mesh, armature, nla...) */
- TransCustomData type;
- } custom;
-#define TRANS_CUSTOM_DATA_ELEM_MAX (sizeof(((TransInfo *)NULL)->custom) / sizeof(TransCustomData))
-
/*************** NEW STUFF *********************/
short launch_event; /* event type used to launch transform */
@@ -484,12 +525,13 @@ typedef struct TransInfo {
struct ReportList *reports; /* assign from the operator, or can be NULL */
int mval[2]; /* current mouse position */
float zfac; /* use for 3d view */
- struct Object *obedit;
- float obedit_mat[3][3]; /* normalized editmode matrix (T_EDIT only) */
void *draw_handle_apply;
void *draw_handle_view;
void *draw_handle_pixel;
void *draw_handle_cursor;
+
+ /** Typically for mode settings. */
+ TransCustomDataContainer custom;
} TransInfo;
@@ -648,7 +690,7 @@ void flushTransSeq(TransInfo *t);
void flushTransTracking(TransInfo *t);
void flushTransMasking(TransInfo *t);
void flushTransPaintCurve(TransInfo *t);
-void restoreBones(TransInfo *t);
+void restoreBones(TransDataContainer *tc);
/*********************** transform_manipulator.c ********** */
@@ -758,6 +800,7 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val
/*********************** Generics ********************************/
+void initTransDataContainers_FromObjectData(TransInfo *t);
void initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, const struct wmEvent *event);
void postTrans(struct bContext *C, TransInfo *t);
void resetTransModal(TransInfo *t);
@@ -773,9 +816,7 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
-void calculateCenterGlobal(
- TransInfo *t, const float center_local[3],
- float r_center_global[3]);
+void calculateCenterLocal(TransInfo *t, const float center_global[3]);
const TransCenterData *transformCenter_from_type(TransInfo *t, int around);
void calculateCenter(TransInfo *t);
@@ -816,11 +857,11 @@ int getTransformOrientation_ex(const struct bContext *C, float normal[3], float
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
void freeEdgeSlideTempFaces(EdgeSlideData *sld);
-void freeEdgeSlideVerts(TransInfo *t, TransCustomData *custom_data);
+void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectEdgeSlideData(TransInfo *t, bool is_final);
void freeVertSlideTempFaces(VertSlideData *sld);
-void freeVertSlideVerts(TransInfo *t, TransCustomData *custom_data);
+void freeVertSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectVertSlideData(TransInfo *t, bool is_final);
@@ -831,4 +872,22 @@ bool checkUseAxisMatrix(TransInfo *t);
#define TRANSFORM_SNAP_MAX_PX 100.0f
#define TRANSFORM_DIST_INVALID -FLT_MAX
+/* Temp macros. */
+
+/* This is to be replaced, just to get things compiling early on. */
+#define TRANS_DATA_CONTAINER_FIRST_EVIL(t) (&(t)->data_container[0])
+#define TRANS_DATA_CONTAINER_FIRST_OK(t) (&(t)->data_container[0])
+/* For cases we _know_ there is only one handle. */
+#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t) (BLI_assert((t)->data_container_len == 1), (&(t)->data_container[0]))
+
+#define FOREACH_TRANS_DATA_CONTAINER(t, th) \
+ for (TransDataContainer *tc = t->data_container, *tc_end = t->data_container + t->data_container_len; \
+ th != tc_end; \
+ th++)
+
+#define FOREACH_TRANS_DATA_CONTAINER_INDEX(t, th, i) \
+ for (TransDataContainer *tc = ((i = 0), t->data_container), *tc_end = t->data_container + t->data_container_len; \
+ th != tc_end; \
+ th++, i++)
+
#endif
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index f612dc0e474..bfaac4933f0 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -333,7 +333,8 @@ static void planeProjection(TransInfo *t, const float in[3], float out[3])
*
*/
-static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3])
+static void applyAxisConstraintVec(
+ TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3], float pvec[3])
{
copy_v3_v3(out, in);
if (!td && t->con.mode & CON_APPLY) {
@@ -380,7 +381,8 @@ static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3
* Further down, that vector is mapped to each data's space.
*/
-static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3])
+static void applyObjectConstraintVec(
+ TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3], float pvec[3])
{
copy_v3_v3(out, in);
if (t->con.mode & CON_APPLY) {
@@ -428,7 +430,7 @@ static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in
mul_m3_v3(td->axismtx, out);
if (t->flag & T_EDIT) {
- mul_m3_v3(t->obedit_mat, out);
+ mul_m3_v3(tc->obedit_mat, out);
}
}
}
@@ -438,7 +440,8 @@ static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in
* Generic callback for constant spatial constraints applied to resize motion
*/
-static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+static void applyAxisConstraintSize(
+ TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, float smat[3][3])
{
if (!td && t->con.mode & CON_APPLY) {
float tmat[3][3];
@@ -462,7 +465,8 @@ static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3
* Callback for object based spatial constraints applied to resize motion
*/
-static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+static void applyObjectConstraintSize(
+ TransInfo *t, TransDataContainer *tc, TransData *td, float smat[3][3])
{
if (td && t->con.mode & CON_APPLY) {
float tmat[3][3];
@@ -482,7 +486,7 @@ static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3]
mul_m3_m3m3(tmat, smat, imat);
if (t->flag & T_EDIT) {
- mul_m3_m3m3(smat, t->obedit_mat, smat);
+ mul_m3_m3m3(smat, tc->obedit_mat, smat);
}
mul_m3_m3m3(smat, td->axismtx, tmat);
}
@@ -502,7 +506,7 @@ static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3]
* (ie: not doing counterclockwise rotations when the mouse moves clockwise).
*/
-static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
+static void applyAxisConstraintRot(TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, float vec[3], float *angle)
{
if (!td && t->con.mode & CON_APPLY) {
int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
@@ -544,7 +548,8 @@ static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], fl
* (ie: not doing counterclockwise rotations when the mouse moves clockwise).
*/
-static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
+static void applyObjectConstraintRot(
+ TransInfo *t, TransDataContainer *tc, TransData *td, float vec[3], float *angle)
{
if (t->con.mode & CON_APPLY) {
int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
@@ -553,11 +558,11 @@ static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3],
/* on setup call, use first object */
if (td == NULL) {
- td = t->data;
+ td = tc->data;
}
if (t->flag & T_EDIT) {
- mul_m3_m3m3(tmp_axismtx, t->obedit_mat, td->axismtx);
+ mul_m3_m3m3(tmp_axismtx, tc->obedit_mat, td->axismtx);
axismtx = tmp_axismtx;
}
else {
@@ -607,20 +612,21 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
- if (t->total == 1) {
+ TransDataContainer *tc = t->data_container;
+ if (t->data_len_all == 1) {
float axismtx[3][3];
if (t->flag & T_EDIT) {
- mul_m3_m3m3(axismtx, t->obedit_mat, t->data->axismtx);
+ mul_m3_m3m3(axismtx, tc->obedit_mat, tc->data->axismtx);
}
else {
- copy_m3_m3(axismtx, t->data->axismtx);
+ copy_m3_m3(axismtx, tc->data->axismtx);
}
setConstraint(t, axismtx, mode, text);
}
else {
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, t->data->axismtx);
+ copy_m3_m3(t->con.mtx, tc->data->axismtx);
t->con.mode = mode;
getConstraintMatrix(t);
@@ -638,7 +644,9 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
{
/* edit-mode now allows local transforms too */
if (t->flag & T_EDIT) {
- setConstraint(t, t->obedit_mat, mode, text);
+ /* Use the active (first) edit object. */
+ TransDataContainer *tc = t->data_container;
+ setConstraint(t, tc->obedit_mat, mode, text);
}
else {
setAxisMatrixConstraint(t, mode, text);
@@ -836,11 +844,12 @@ static void drawObjectConstraint(TransInfo *t)
* Without drawing the first light, users have little clue what they are doing.
*/
short options = DRAWLIGHT;
- TransData *td = t->data;
int i;
float tmp_axismtx[3][3];
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
float co[3];
float (*axismtx)[3];
@@ -863,13 +872,13 @@ static void drawObjectConstraint(TransInfo *t)
axismtx = td->axismtx;
}
else if (t->flag & T_EDIT) {
- mul_v3_m4v3(co, t->obedit->obmat, td->center);
+ mul_v3_m4v3(co, tc->obedit->obmat, td->center);
- mul_m3_m3m3(tmp_axismtx, t->obedit_mat, td->axismtx);
+ mul_m3_m3m3(tmp_axismtx, tc->obedit_mat, td->axismtx);
axismtx = tmp_axismtx;
}
else if (t->flag & T_POSE) {
- mul_v3_m4v3(co, t->poseobj->obmat, td->center);
+ mul_v3_m4v3(co, tc->poseobj->obmat, td->center);
axismtx = td->axismtx;
}
else {
@@ -888,6 +897,7 @@ static void drawObjectConstraint(TransInfo *t)
}
options &= ~DRAWLIGHT;
}
+ }
}
/*--------------------- START / STOP CONSTRAINTS ---------------------- */
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index fff124c8995..936985d4cb9 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -130,7 +130,7 @@
*/
static void transform_around_single_fallback(TransInfo *t)
{
- if ((t->total == 1) &&
+ if ((t->data_len_all == 1) &&
(ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEAN, V3D_AROUND_ACTIVE)) &&
(ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
{
@@ -171,27 +171,31 @@ static int trans_data_compare_rdist(const void *a, const void *b)
void sort_trans_data_dist(TransInfo *t)
{
- TransData *start = t->data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *start = tc->data;
int i;
- for (i = 0; i < t->total && start->flag & TD_SELECTED; i++)
+ for (i = 0; i < tc->data_len && start->flag & TD_SELECTED; i++) {
start++;
-
- if (i < t->total) {
+ }
+
+ if (i < tc->data_len) {
if (t->flag & T_PROP_CONNECTED)
- qsort(start, t->total - i, sizeof(TransData), trans_data_compare_dist);
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_dist);
else
- qsort(start, t->total - i, sizeof(TransData), trans_data_compare_rdist);
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_rdist);
+ }
}
}
static void sort_trans_data(TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *sel, *unsel;
TransData temp;
- unsel = t->data;
- sel = t->data;
- sel += t->total - 1;
+ unsel = tc->data;
+ sel = tc->data;
+ sel += tc->data_len - 1;
while (sel > unsel) {
while (unsel->flag & TD_SELECTED) {
unsel++;
@@ -211,13 +215,13 @@ static void sort_trans_data(TransInfo *t)
sel--;
unsel++;
}
+ }
}
/* distance calculated from not-selected vertex to nearest selected vertex
* warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
static void set_prop_dist(TransInfo *t, const bool with_dist)
{
- TransData *tob;
int a;
float _proj_vec[3];
@@ -234,7 +238,9 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
}
}
- for (a = 0, tob = t->data; a < t->total; a++, tob++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *tob = tc->data;
+ for (a = 0; a < tc->data_len; a++, tob++) {
tob->rdist = 0.0f; // init, it was mallocced
@@ -245,7 +251,7 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
tob->rdist = -1.0f; // signal for next loop
- for (i = 0, td = t->data; i < t->total; i++, td++) {
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
if (td->flag & TD_SELECTED) {
if (use_island) {
sub_v3_v3v3(vec, tob->iloc, td->iloc);
@@ -279,6 +285,7 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
}
}
}
+ }
}
/* ************************** CONVERSIONS ************************* */
@@ -296,26 +303,32 @@ static void createTransTexspace(TransInfo *t)
ob = OBACT(view_layer);
if (ob == NULL) { // Shouldn't logically happen, but still...
- t->total = 0;
+ t->data_len_all = 0;
return;
}
id = ob->data;
if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
- t->total = 0;
+ t->data_len_all = 0;
return;
}
if (BKE_object_obdata_is_libdata(ob)) {
BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
- t->total = 0;
+ t->data_len_all = 0;
return;
}
- t->total = 1;
- td = t->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = t->ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+
+ {
+ TransDataContainer *tc = t->data_container = MEM_callocN(sizeof(*t->data_container), __func__);
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ t->data_len_all = 1;
td->flag = TD_SELECTED;
copy_v3_v3(td->center, ob->obmat[3]);
@@ -340,7 +353,9 @@ static void createTransTexspace(TransInfo *t)
static void createTransEdge(TransInfo *t)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
TransData *td = NULL;
BMEdge *eed;
BMIter iter;
@@ -356,29 +371,31 @@ static void createTransEdge(TransInfo *t)
}
}
- if (countsel == 0)
- return;
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
if (is_prop_edit) {
- t->total = count;
+ tc->data_len = count;
}
else {
- t->total = countsel;
+ tc->data_len = countsel;
}
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransCrease");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease");
- copy_m3_m4(mtx, t->obedit->obmat);
+ copy_m3_m4(mtx, tc->obedit->obmat);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
/* create data we need */
if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_EDGE_BWEIGHT);
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
}
else { //if (t->mode == TFM_CREASE) {
BLI_assert(t->mode == TFM_CREASE);
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_EDGE_CREASE);
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
}
@@ -408,6 +425,7 @@ static void createTransEdge(TransInfo *t)
td++;
}
}
+ }
}
/* ********************* pose mode ************* */
@@ -523,7 +541,7 @@ static short apply_targetless_ik(Object *ob)
return apply;
}
-static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td)
+static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
{
Bone *bone = pchan->bone;
float pmat[3][3], omat[3][3];
@@ -634,7 +652,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
normalize_m3(td->axismtx);
if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- bArmature *arm = t->poseobj->data;
+ bArmature *arm = tc->poseobj->data;
if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
@@ -828,15 +846,20 @@ void transform_autoik_update(TransInfo *t, short mode)
}
}
- /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
- if (ELEM(NULL, t->poseobj, t->poseobj->pose))
- return;
-
/* apply to all pose-channels */
bool changed = false;
- for (pchan = t->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
+ if (ELEM(NULL, tc->poseobj, tc->poseobj->pose)) {
+ continue;
+ }
+
+ for (pchan = tc->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
changed |= pchan_autoik_adjust(pchan, *chainlen);
}
+ }
if (changed) {
/* TODO(sergey): Consider doing partial update only. */
@@ -1045,9 +1068,28 @@ static short pose_grab_with_ik(Object *ob)
}
-/* only called with pose mode active object now */
-static void createTransPose(TransInfo *t, Object *ob)
+/**
+ * When objects array is NULL, use 't->data_container' as is.
+ */
+static void createTransPose(TransInfo *t, Object **objects, uint objects_len)
{
+ if (objects != NULL) {
+ if (t->data_container) {
+ MEM_freeN(t->data_container);
+ }
+ t->data_container = MEM_callocN(sizeof(*t->data_container) * objects_len, __func__);
+ t->data_container_len = objects_len;
+ int th_index;
+ FOREACH_TRANS_DATA_CONTAINER_INDEX (t, tc, th_index) {
+ tc->poseobj = objects[th_index];
+ }
+ }
+
+ t->data_len_all = 0;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
+
bArmature *arm;
bPoseChannel *pchan;
TransData *td;
@@ -1055,11 +1097,12 @@ static void createTransPose(TransInfo *t, Object *ob)
short ik_on = 0;
int i;
- t->total = 0;
/* check validity of state */
- arm = BKE_armature_from_object(ob);
- if ((arm == NULL) || (ob->pose == NULL)) return;
+ arm = BKE_armature_from_object(tc->poseobj);
+ if ((arm == NULL) || (ob->pose == NULL)) {
+ continue;
+ }
if (arm->flag & ARM_RESTPOS) {
if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
@@ -1075,45 +1118,51 @@ static void createTransPose(TransInfo *t, Object *ob)
}
/* set flags and count total (warning, can change transform to rotate) */
- t->total = count_set_pose_transflags(&t->mode, t->around, ob);
+ tc->data_len = count_set_pose_transflags(&t->mode, t->around, ob);
- if (t->total == 0) return;
+ if (tc->data_len == 0) {
+ continue;
+ }
- t->flag |= T_POSE;
- t->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
-
- /* disable PET, its not usable in pose mode yet [#32444] */
- t->flag &= ~T_PROP_EDIT_ALL;
+ tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
/* init trans data */
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransPoseBone");
- tdx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "TransPoseBoneExt");
- for (i = 0; i < t->total; i++, td++, tdx++) {
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransPoseBone");
+ tdx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransPoseBoneExt");
+ for (i = 0; i < tc->data_len; i++, td++, tdx++) {
td->ext = tdx;
td->val = NULL;
}
/* use pose channels to fill trans data */
- td = t->data;
+ td = tc->data;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone->flag & BONE_TRANSFORM) {
- add_pose_transdata(t, pchan, ob, td);
+ add_pose_transdata(t, pchan, ob, tc, td);
td++;
}
}
- if (td != (t->data + t->total)) {
+ if (td != (tc->data + tc->data_len)) {
BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
}
/* initialize initial auto=ik chainlen's? */
- if (ik_on) transform_autoik_update(t, 0);
+ if (ik_on) {
+ transform_autoik_update(t, 0);
+ }
+ }
+
+ t->flag |= T_POSE;
+ /* disable PET, its not usable in pose mode yet [#32444] */
+ t->flag &= ~T_PROP_EDIT_ALL;
+
}
-void restoreBones(TransInfo *t)
+void restoreBones(TransDataContainer *tc)
{
- bArmature *arm = t->obedit->data;
- BoneInitData *bid = t->custom.type.data;
+ bArmature *arm = tc->obedit->data;
+ BoneInitData *bid = tc->custom.type.data;
EditBone *ebo;
while (bid->bone) {
@@ -1154,8 +1203,9 @@ void restoreBones(TransInfo *t)
/* ********************* armature ************** */
static void createTransArmatureVerts(TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
EditBone *ebo, *eboflip;
- bArmature *arm = t->obedit->data;
+ bArmature *arm = tc->obedit->data;
ListBase *edbo = arm->edbo;
TransData *td, *td_old;
float mtx[3][3], smtx[3][3], bonemat[3][3];
@@ -1164,46 +1214,48 @@ static void createTransArmatureVerts(TransInfo *t)
int oldtot;
BoneInitData *bid;
- t->total = 0;
+ tc->data_len = 0;
for (ebo = edbo->first; ebo; ebo = ebo->next) {
- oldtot = t->total;
+ oldtot = tc->data_len;
if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
if (ebo->flag & BONE_SELECTED)
- t->total++;
+ tc->data_len++;
}
else if (t->mode == TFM_BONE_ROLL) {
if (ebo->flag & BONE_SELECTED)
- t->total++;
+ tc->data_len++;
}
else {
if (ebo->flag & BONE_TIPSEL)
- t->total++;
+ tc->data_len++;
if (ebo->flag & BONE_ROOTSEL)
- t->total++;
+ tc->data_len++;
}
}
- if (mirror && (oldtot < t->total)) {
+ if (mirror && (oldtot < tc->data_len)) {
eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
if (eboflip)
total_mirrored++;
}
}
- if (!t->total) return;
+ if (!tc->data_len) {
+ continue;
+ }
transform_around_single_fallback(t);
- copy_m3_m4(mtx, t->obedit->obmat);
+ copy_m3_m4(mtx, tc->obedit->obmat);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransEditBone");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone");
if (mirror) {
- t->custom.type.data = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
- t->custom.type.use_free = true;
+ tc->custom.type.data = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
+ tc->custom.type.use_free = true;
}
i = 0;
@@ -1226,7 +1278,7 @@ static void createTransArmatureVerts(TransInfo *t)
td->loc = NULL;
td->ext = NULL;
- td->ob = t->obedit;
+ td->ob = tc->obedit;
td++;
}
@@ -1241,7 +1293,7 @@ static void createTransArmatureVerts(TransInfo *t)
td->loc = NULL;
td->ext = NULL;
- td->ob = t->obedit;
+ td->ob = tc->obedit;
td++;
}
@@ -1272,7 +1324,7 @@ static void createTransArmatureVerts(TransInfo *t)
normalize_m3(td->axismtx);
td->ext = NULL;
- td->ob = t->obedit;
+ td->ob = tc->obedit;
td++;
}
@@ -1287,7 +1339,7 @@ static void createTransArmatureVerts(TransInfo *t)
td->flag = TD_SELECTED;
td->ext = NULL;
- td->ob = t->obedit;
+ td->ob = tc->obedit;
td++;
}
@@ -1326,7 +1378,7 @@ static void createTransArmatureVerts(TransInfo *t)
td->ext = NULL;
td->val = NULL;
- td->ob = t->obedit;
+ td->ob = tc->obedit;
td++;
}
@@ -1348,7 +1400,7 @@ static void createTransArmatureVerts(TransInfo *t)
td->ext = NULL;
td->val = NULL;
- td->ob = t->obedit;
+ td->ob = tc->obedit;
td++;
}
@@ -1375,13 +1427,15 @@ static void createTransArmatureVerts(TransInfo *t)
/* trick to terminate iteration */
bid[total_mirrored].bone = NULL;
}
+ }
}
/* ********************* meta elements ********* */
static void createTransMBallVerts(TransInfo *t)
{
- MetaBall *mb = (MetaBall *)t->obedit->data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ MetaBall *mb = (MetaBall *)tc->obedit->data;
MetaElem *ml;
TransData *td;
TransDataExtension *tx;
@@ -1396,15 +1450,17 @@ static void createTransMBallVerts(TransInfo *t)
}
/* note: in prop mode we need at least 1 selected */
- if (countsel == 0) return;
+ if (countsel == 0) {
+ continue;
+ }
- if (is_prop_edit) t->total = count;
- else t->total = countsel;
+ if (is_prop_edit) tc->data_len = count;
+ else tc->data_len = countsel;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)");
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "MetaElement_TransExtension");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(MBall EditMode)");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "MetaElement_TransExtension");
- copy_m3_m4(mtx, t->obedit->obmat);
+ copy_m3_m4(mtx, tc->obedit->obmat);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
for (ml = mb->editelems->first; ml; ml = ml->next) {
@@ -1449,6 +1505,7 @@ static void createTransMBallVerts(TransInfo *t)
tx++;
}
}
+ }
}
/* ********************* curve/surface ********* */
@@ -1555,7 +1612,9 @@ static int bezt_select_to_transform_triple_flag(
static void createTransCurveVerts(TransInfo *t)
{
- Curve *cu = t->obedit->data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ Curve *cu = tc->obedit->data;
TransData *td = NULL;
Nurb *nu;
BezTriple *bezt;
@@ -1599,18 +1658,21 @@ static void createTransCurveVerts(TransInfo *t)
}
}
/* note: in prop mode we need at least 1 selected */
- if (countsel == 0) return;
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
- if (is_prop_edit) t->total = count;
- else t->total = countsel;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)");
+ if (is_prop_edit) tc->data_len = count;
+ else tc->data_len = countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)");
transform_around_single_fallback(t);
- copy_m3_m4(mtx, t->obedit->obmat);
+ copy_m3_m4(mtx, tc->obedit->obmat);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- td = t->data;
+ td = tc->data;
for (nu = nurbs->first; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
TransData *head, *tail;
@@ -1819,7 +1881,7 @@ static void createTransCurveVerts(TransInfo *t)
calc_distanceCurveVerts(head, tail - 1);
}
}
-
+ }
#undef SEL_F1
#undef SEL_F2
#undef SEL_F3
@@ -1829,7 +1891,9 @@ static void createTransCurveVerts(TransInfo *t)
static void createTransLatticeVerts(TransInfo *t)
{
- Lattice *latt = ((Lattice *)t->obedit->data)->editlatt->latt;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ Lattice *latt = ((Lattice *)tc->obedit->data)->editlatt->latt;
TransData *td = NULL;
BPoint *bp;
float mtx[3][3], smtx[3][3];
@@ -1850,14 +1914,14 @@ static void createTransLatticeVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (is_prop_edit) t->total = count;
- else t->total = countsel;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)");
+ if (is_prop_edit) tc->data_len = count;
+ else tc->data_len = countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)");
- copy_m3_m4(mtx, t->obedit->obmat);
+ copy_m3_m4(mtx, tc->obedit->obmat);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- td = t->data;
+ td = tc->data;
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
@@ -1884,11 +1948,14 @@ static void createTransLatticeVerts(TransInfo *t)
}
bp++;
}
+ }
}
/* ******************* particle edit **************** */
static void createTransParticleVerts(bContext *C, TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
TransData *td = NULL;
TransDataExtension *tx;
Object *ob = CTX_data_active_object(C);
@@ -1936,13 +2003,13 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (hasselected == 0) return;
- t->total = count;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Particle Mode)");
+ tc->data_len = count;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Particle Mode)");
if (t->mode == TFM_BAKE_TIME)
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "Particle_TransExtension");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "Particle_TransExtension");
else
- tx = t->ext = NULL;
+ tx = tc->data_ext = NULL;
unit_m4(mat);
@@ -2003,10 +2070,13 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
+ }
}
void flushTransParticles(TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
Scene *scene = t->scene;
ViewLayer *view_layer = t->view_layer;
Object *ob = OBACT(view_layer);
@@ -2025,7 +2095,7 @@ void flushTransParticles(TransInfo *t)
/* we do transform in world space, so flush world space position
* back to particle local space (only for hair particles) */
- td = t->data;
+ td = tc->data;
for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
if (!(point->flag & PEP_TRANSFORM)) continue;
@@ -2050,6 +2120,7 @@ void flushTransParticles(TransInfo *t)
}
PE_update_object(&t->eval_ctx, scene, OBACT(view_layer), 1);
+ }
}
/* ********************* mesh ****************** */
@@ -2459,10 +2530,12 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
static void createTransEditVerts(TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
TransData *tob = NULL;
TransDataExtension *tx = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
- Mesh *me = t->obedit->data;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ Mesh *me = tc->obedit->data;
BMesh *bm = em->bm;
BMVert *eve;
BMIter iter;
@@ -2486,8 +2559,11 @@ static void createTransEditVerts(TransInfo *t)
int *dists_index = NULL;
if (t->flag & T_MIRROR) {
- EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
- mirror = 1;
+ /* TODO(campbell): xform: We need support for many mirror objects at once! */
+ if (tc->is_active) {
+ EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
+ mirror = 1;
+ }
}
/**
@@ -2501,7 +2577,7 @@ static void createTransEditVerts(TransInfo *t)
}
if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_VERT_BWEIGHT);
+ BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
@@ -2513,7 +2589,7 @@ static void createTransEditVerts(TransInfo *t)
}
}
- t->total = count;
+ tc->data_len = count;
/* allocating scratch arrays */
if (prop_mode & T_PROP_CONNECTED) {
@@ -2524,20 +2600,19 @@ static void createTransEditVerts(TransInfo *t)
}
}
else {
- t->total = bm->totvertsel;
+ tc->data_len = bm->totvertsel;
}
- tob = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mesh EditMode)");
+ tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
/* warning, this is overkill, we only need 2 extra floats,
* but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
* since we may not use the 'alt' transform mode to maintain shell thickness,
* but with generic transform code its hard to lazy init vars */
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension),
- "TransObData ext");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObData ext");
}
- copy_m3_m4(mtx, t->obedit->obmat);
+ copy_m3_m4(mtx, tc->obedit->obmat);
/* we use a pseudoinverse so that when one of the axes is scaled to 0,
* matrix inversion still works and we can still moving along the other */
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
@@ -2557,12 +2632,12 @@ static void createTransEditVerts(TransInfo *t)
}
/* detect CrazySpace [tm] */
- if (modifiers_getCageIndex(t->scene, t->obedit, NULL, 1) != -1) {
+ if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
int totleft = -1;
- if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) {
+ if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
/* check if we can use deform matrices for modifier from the
* start up to stack, they are more accurate than quats */
- totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(&t->eval_ctx, t->scene, t->obedit, em, &defmats, &defcos);
+ totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(&t->eval_ctx, t->scene, tc->obedit, em, &defmats, &defcos);
}
/* if we still have more modifiers, also do crazyspace
@@ -2575,7 +2650,7 @@ static void createTransEditVerts(TransInfo *t)
if (totleft > 0)
#endif
{
- mappedcos = BKE_crazyspace_get_mapped_editverts(&t->eval_ctx, t->scene, t->obedit);
+ mappedcos = BKE_crazyspace_get_mapped_editverts(&t->eval_ctx, t->scene, tc->obedit);
quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
if (mappedcos)
@@ -2675,8 +2750,8 @@ static void createTransEditVerts(TransInfo *t)
}
if (mirror != 0) {
- tob = t->data;
- for (a = 0; a < t->total; a++, tob++) {
+ tob = tc->data;
+ for (a = 0; a < tc->data_len; a++, tob++) {
if (ABS(tob->loc[0]) <= 0.00001f) {
tob->flag |= TD_MIRROR_EDGE;
}
@@ -2697,12 +2772,15 @@ cleanup:
if (t->flag & T_MIRROR) {
EDBM_verts_mirror_cache_end(em);
}
+ }
}
/* *** NODE EDITOR *** */
void flushTransNodes(TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
int a;
TransData *td;
TransData2D *td2d;
@@ -2710,7 +2788,7 @@ void flushTransNodes(TransInfo *t)
applyGridAbsolute(t);
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
bNode *node = td->extra;
float locx, locy;
@@ -2732,11 +2810,12 @@ void flushTransNodes(TransInfo *t)
node->locy = locy;
}
}
-
+
/* handle intersection with noodles */
- if (t->total == 1) {
+ if (tc->data_len == 1) {
ED_node_link_intersect_test(t->sa, 1);
}
+ }
}
/* *** SEQUENCE EDITOR *** */
@@ -2765,13 +2844,14 @@ BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int s
void flushTransSeq(TransInfo *t)
{
ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep; /* Editing null check already done */
+
int a, new_frame;
TransData *td = NULL;
TransData2D *td2d = NULL;
TransDataSeq *tdsq = NULL;
Sequence *seq;
-
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* prevent updating the same seq twice
* if the transdata order is changed this will mess up
@@ -2780,7 +2860,7 @@ void flushTransSeq(TransInfo *t)
int old_start_prev = 0, sel_flag_prev = 0;
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
int old_start;
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
@@ -2853,8 +2933,8 @@ void flushTransSeq(TransInfo *t)
}
/* update effects inside meta's */
- for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d;
- a < t->total;
+ for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d;
+ a < tc->data_len;
a++, td++, td2d++, seq_prev = seq)
{
tdsq = (TransDataSeq *)td->extra;
@@ -2870,7 +2950,7 @@ void flushTransSeq(TransInfo *t)
/* need to do the overlap check in a new loop otherwise adjacent strips
* will not be updated and we'll get false positives */
seq_prev = NULL;
- for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
@@ -2931,22 +3011,27 @@ static void createTransUVs(bContext *C, TransInfo *t)
Image *ima = CTX_data_edit_image(C);
Scene *scene = t->scene;
ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
TransData *td = NULL;
TransData2D *td2d = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMFace *efa;
BMIter iter, liter;
UvElementMap *elementmap = NULL;
BLI_bitmap *island_enabled = NULL;
struct { float co[2]; int co_num; } *island_center = NULL;
int count = 0, countsel = 0, count_rejected = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
- const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (!ED_space_image_show_uvedit(sima, t->obedit))
- return;
+ if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
+ continue;
+ }
/* count */
if (is_prop_connected || is_island_center) {
@@ -2969,7 +3054,7 @@ static void createTransUVs(bContext *C, TransInfo *t)
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMLoop *l;
- if (!uvedit_face_visible_test(scene, t->obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
continue;
}
@@ -3017,17 +3102,17 @@ static void createTransUVs(bContext *C, TransInfo *t)
}
}
- t->total = (is_prop_edit) ? count : countsel;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)");
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(UV Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
- t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransObData2D(UV Editing)");
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(UV Editing)");
if (sima->flag & SI_CLIP_UV)
t->flag |= T_CLIP_UV;
- td = t->data;
- td2d = t->data2d;
+ td = tc->data;
+ td2d = tc->data_2d;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMLoop *l;
@@ -3065,12 +3150,16 @@ static void createTransUVs(bContext *C, TransInfo *t)
}
if (is_prop_connected) {
- t->total -= count_rejected;
+ tc->data_len -= count_rejected;
}
- if (sima->flag & SI_LIVE_UNWRAP)
- ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
-
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ /* TODO(campbell): xform: Only active object currently!
+ * it uses a static variable. */
+ if (tc->is_active) {
+ ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
+ }
+ }
finally:
if (is_prop_connected || is_island_center) {
@@ -3084,15 +3173,18 @@ finally:
MEM_freeN(island_center);
}
}
+ }
}
void flushTransUVs(TransInfo *t)
{
SpaceImage *sima = t->sa->spacedata.first;
+ const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL));
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData2D *td;
int a;
float aspect_inv[2], size[2];
- const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL));
aspect_inv[0] = 1.0f / t->aspect[0];
aspect_inv[1] = 1.0f / t->aspect[1];
@@ -3105,7 +3197,7 @@ void flushTransUVs(TransInfo *t)
}
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data2d; a < t->total; a++, td++) {
+ for (a = 0, td = tc->data_2d; a < tc->data_len; a++, td++) {
td->loc2d[0] = td->loc[0] * aspect_inv[0];
td->loc2d[1] = td->loc[1] * aspect_inv[1];
@@ -3114,12 +3206,11 @@ void flushTransUVs(TransInfo *t)
td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
}
}
+ }
}
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
{
- TransData *td;
- int a;
bool clipx = true, clipy = true;
float min[2], max[2];
@@ -3127,22 +3218,27 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
max[0] = t->aspect[0];
max[1] = t->aspect[1];
- for (a = 0, td = t->data; a < t->total; a++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td;
+ int a;
+
+ for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
minmax_v2v2_v2(min, max, td->loc);
}
if (resize) {
- if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < t->aspect[0] * 0.5f)
- vec[0] *= t->center[0] / (t->center[0] - min[0]);
- else if (max[0] > t->aspect[0] && t->center[0] < t->aspect[0])
- vec[0] *= (t->center[0] - t->aspect[0]) / (t->center[0] - max[0]);
+ if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f)
+ vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
+ else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0])
+ vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
else
clipx = 0;
- if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < t->aspect[1] * 0.5f)
- vec[1] *= t->center[1] / (t->center[1] - min[1]);
- else if (max[1] > t->aspect[1] && t->center[1] < t->aspect[1])
- vec[1] *= (t->center[1] - t->aspect[1]) / (t->center[1] - max[1]);
+ if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f)
+ vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
+ else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1])
+ vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
else
clipy = 0;
}
@@ -3161,16 +3257,16 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
else
clipy = 0;
}
+ }
return (clipx || clipy);
}
void clipUVData(TransInfo *t)
{
- TransData *td = NULL;
- int a;
-
- for (a = 0, td = t->data; a < t->total; a++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (int a = 0; a < tc->data_len; a++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -3180,6 +3276,7 @@ void clipUVData(TransInfo *t)
td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
}
+ }
}
/* ********************* ANIMATION EDITORS (GENERAL) ************************* */
@@ -3212,7 +3309,9 @@ static void createTransNlaData(bContext *C, TransInfo *t)
int filter;
int count = 0;
-
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
@@ -3272,12 +3371,12 @@ static void createTransNlaData(bContext *C, TransInfo *t)
}
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(NLA Editor)");
- td = t->data;
- t->custom.type.data = tdn = MEM_callocN(t->total * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
- t->custom.type.use_free = true;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
+ td = tc->data;
+ tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
+ tc->custom.type.use_free = true;
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -3807,11 +3906,11 @@ typedef struct tGPFtransdata {
/* This function helps flush transdata written to tempdata into the gp-frames */
void flushTransIntFrameActionData(TransInfo *t)
{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
tGPFtransdata *tfd = t->custom.type.data;
- int i;
/* flush data! */
- for (i = 0; i < t->total; i++, tfd++) {
+ for (int i = 0; i < tc->data_len; i++, tfd++) {
*(tfd->sdata) = round_fl_to_int(tfd->val);
}
}
@@ -3967,18 +4066,20 @@ static void createTransActionData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
return;
}
-
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(Action Editor)");
- t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "transdata2d");
- td = t->data;
- td2d = t->data2d;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
+ td = tc->data;
+ td2d = tc->data_2d;
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- t->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
- t->custom.type.use_free = true;
+ tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
+ tc->custom.type.use_free = true;
}
/* loop 2: build transdata array */
@@ -4023,7 +4124,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* calculate distances for proportional editing */
if (is_prop_edit) {
- td = t->data;
+ td = tc->data;
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt;
@@ -4365,19 +4466,21 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
return;
}
-
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData (Graph Editor)");
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData (Graph Editor)");
/* for each 2d vert a 3d vector is allocated, so that they can be treated just as if they were 3d verts */
- t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D (Graph Editor)");
- t->custom.type.data = MEM_callocN(t->total * sizeof(TransDataGraph), "TransDataGraph");
- t->custom.type.use_free = true;
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D (Graph Editor)");
+ tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataGraph), "TransDataGraph");
+ tc->custom.type.use_free = true;
- td = t->data;
- td2d = t->data2d;
- tdg = t->custom.type.data;
+ td = tc->data;
+ td2d = tc->data_2d;
+ tdg = tc->custom.type.data;
/* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
unit_m3(mtx);
@@ -4504,7 +4607,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (is_prop_edit) {
/* loop 2: build transdata arrays */
- td = t->data;
+ td = tc->data;
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
@@ -4660,12 +4763,14 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
TransData *td;
int i, j;
char *adjusted;
-
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* dynamically allocate an array of chars to mark whether an TransData's
* pointers have been fixed already, so that we don't override ones that are
* already done
*/
- adjusted = MEM_callocN(t->total, "beztmap_adjusted_map");
+ adjusted = MEM_callocN(tc->data_len, "beztmap_adjusted_map");
/* for each beztmap item, find if it is used anywhere */
bezm = bezms;
@@ -4673,9 +4778,9 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
/* loop through transdata, testing if we have a hit
* for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
*/
- td2d = t->data2d;
- td = t->data;
- for (j = 0; j < t->total; j++, td2d++, td++) {
+ td2d = tc->data_2d;
+ td = tc->data;
+ for (j = 0; j < tc->data_len; j++, td2d++, td++) {
/* skip item if already marked */
if (adjusted[j] != 0) continue;
@@ -4778,9 +4883,11 @@ void flushTransGraphData(TransInfo *t)
double secf = FPS;
int a;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d, tdg = t->custom.type.data;
- a < t->total;
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdg = tc->custom.type.data;
+ a < tc->data_len;
a++, td++, td2d++, tdg++)
{
AnimData *adt = (AnimData *)td->extra; /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
@@ -5142,13 +5249,15 @@ static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
}
-static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
+static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
{
Editing *ed = BKE_sequencer_editing_get(t->scene, false);
if (ed != NULL) {
+
+
ListBase *seqbasep = ed->seqbasep;
- TransData *td = t->data;
+ TransData *td = tc->data;
int a;
/* prevent updating the same seq twice
@@ -5176,7 +5285,7 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
{
int overlap = 0;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
overlap = 1;
@@ -5189,8 +5298,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
for (seq = seqbasep->first; seq; seq = seq->next)
seq->tmp = NULL;
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
/* check effects strips, we cant change their time */
@@ -5213,8 +5322,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
if (t->flag & T_ALT_TRANSFORM) {
int minframe = MAXFRAME;
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0)) {
minframe = min_ii(minframe, seq->startdisp);
@@ -5250,8 +5359,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
if (has_effect_any) {
/* update effects strips based on strips just moved in time */
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5263,8 +5372,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
if (has_effect_root) {
/* now if any effects _still_ overlap, we need to move them up */
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5293,7 +5402,7 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
}
else {
/* Canceled, need to update the strips display */
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0; a < tc->data_len; a++, td++) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0)) {
if (seq->flag & SEQ_OVERLAP)
@@ -5312,9 +5421,9 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
MEM_freeN(custom_data->data);
custom_data->data = NULL;
}
- if (t->data) {
- MEM_freeN(t->data); // XXX postTrans usually does this
- t->data = NULL;
+ if (tc->data) {
+ MEM_freeN(tc->data); // XXX postTrans usually does this
+ tc->data = NULL;
}
}
@@ -5333,12 +5442,14 @@ static void createTransSeqData(bContext *C, TransInfo *t)
int count = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
if (ed == NULL) {
- t->total = 0;
+ tc->data_len = 0;
return;
}
- t->custom.type.free_cb = freeSeqData;
+ tc->custom.type.free_cb = freeSeqData;
xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
@@ -5377,18 +5488,18 @@ static void createTransSeqData(bContext *C, TransInfo *t)
count = SeqTransCount(t, NULL, ed->seqbasep, 0);
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
/* stop if trying to build list if nothing selected */
if (count == 0) {
return;
}
- t->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
- t->custom.type.use_free = true;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransSeq TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransSeq TransData2D");
- ts->tdseq = tdsq = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq");
+ tc->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
+ tc->custom.type.use_free = true;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D");
+ ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
/* loop 2: build transdata array */
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
@@ -6118,9 +6229,11 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
/* so automerge supports mirror */
if ((t->scene->toolsettings->automerge) &&
- (t->obedit && t->obedit->type == OB_MESH))
+ ((t->flag & T_EDIT) && t->obedit_type == OB_MESH))
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
char hflag;
bool has_face_sel = (bm->totfacesel != 0);
@@ -6133,7 +6246,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
* tag all mirrored verts, then automerge those */
BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
if (td->extra) {
BM_elem_flag_enable((BMVert *)td->extra, BM_ELEM_TAG);
}
@@ -6145,7 +6258,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
hflag = BM_ELEM_SELECT;
}
- EDBM_automerge(t->scene, t->obedit, true, hflag);
+ EDBM_automerge(t->scene, tc->obedit, true, hflag);
/* Special case, this is needed or faces won't re-select.
* Flush selected edges to faces. */
@@ -6153,6 +6266,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
}
}
+ }
}
/* inserting keys, pointcache, redraw events... */
@@ -6168,50 +6282,53 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
/* early out when nothing happened */
- if (t->total == 0 || t->mode == TFM_DUMMY)
+ if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
return;
-
+ }
+
if (t->spacetype == SPACE_VIEW3D) {
- if (t->obedit) {
+ if (t->flag & T_EDIT) {
/* Special Exception:
* We don't normally access 't->custom.mode' here, but its needed in this case. */
if (canceled == 0) {
/* we need to delete the temporary faces before automerging */
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->custom.mode.data;
-
/* handle multires re-projection, done
* on transform completion since it's
* really slow -joeedh */
projectEdgeSlideData(t, true);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+
/* free temporary faces to avoid automerging and deleting
* during cleanup - psy-fi */
freeEdgeSlideTempFaces(sld);
+ }
}
else if (t->mode == TFM_VERT_SLIDE) {
/* as above */
- VertSlideData *sld = t->custom.mode.data;
projectVertSlideData(t, true);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
freeVertSlideTempFaces(sld);
+ }
}
- if (t->obedit->type == OB_MESH) {
+ if (t->obedit_type == OB_MESH) {
special_aftertrans_update__mesh(C, t);
}
}
else {
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->custom.mode.data;
-
- sld->perc = 0.0;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
projectEdgeSlideData(t, false);
}
else if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = t->custom.mode.data;
-
- sld->perc = 0.0;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
projectVertSlideData(t, false);
}
}
@@ -6485,26 +6602,33 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
ED_nla_postop_refresh(&ac);
}
}
- else if (t->obedit) {
- if (t->obedit->type == OB_MESH) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
- /* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(t->obedit, em, NULL, NULL, 'e');
+ else if (t->flag & T_EDIT) {
+ if (t->obedit_type == OB_MESH) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ /* table needs to be created for each edit command, since vertices can move etc */
+ ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
+ /* TODO(campbell): xform: We need support for many mirror objects at once! */
+ break;
+ }
}
}
- else if ((t->flag & T_POSE) && (t->poseobj)) {
+ else if (t->flag & T_POSE) {
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
bArmature *arm;
bPoseChannel *pchan;
short targetless_ik = 0;
- ob = t->poseobj;
+ ob = tc->poseobj;
arm = ob->data;
if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
/* when running transform non-interactively (operator exec),
* we need to update the pose otherwise no updates get called during
* transform and the auto-ik is not applied. see [#26164] */
- struct Object *pose_ob = t->poseobj;
+ struct Object *pose_ob = tc->poseobj;
BKE_pose_where_is(&t->eval_ctx, t->scene, pose_ob);
}
@@ -6542,7 +6666,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else {
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
-
+ }
}
else if (t->options & CTX_PAINT_CURVE) {
/* pass */
@@ -6559,8 +6683,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
BLI_assert(t->flag & (T_OBJECT | T_TEXTURE));
- for (i = 0; i < t->total; i++) {
- TransData *td = t->data + i;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ for (i = 0; i < tc->data_len; i++) {
+ TransData *td = tc->data + i;
ListBase pidlist;
PTCacheID *pid;
ob = td->ob;
@@ -6614,7 +6740,7 @@ int special_transform_moving(TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
return G_TRANSFORM_FCURVES;
}
- else if (t->obedit || ((t->flag & T_POSE) && (t->poseobj))) {
+ else if ((t->flag & T_EDIT) || (t->flag & T_POSE)) {
return G_TRANSFORM_EDIT;
}
else if (t->flag & (T_OBJECT | T_TEXTURE)) {
@@ -6632,21 +6758,23 @@ static void createTransObject(bContext *C, TransInfo *t)
set_trans_object_base_flags(t);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* count */
- t->total = CTX_DATA_COUNT(C, selected_objects);
+ tc->data_len = CTX_DATA_COUNT(C, selected_objects);
- if (!t->total) {
+ if (!tc->data_len) {
/* clear here, main transform function escapes too */
clear_trans_object_base_flags(t);
return;
}
if (is_prop_edit) {
- t->total += count_proportional_objects(t);
+ tc->data_len += count_proportional_objects(t);
}
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransOb");
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "TransObExtension");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransOb");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObExtension");
CTX_DATA_BEGIN(C, Base *, base, selected_bases)
{
@@ -6766,7 +6894,9 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
SpaceNode *snode = t->sa->spacedata.first;
bNode *node;
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!snode->edittree) {
return;
@@ -6779,15 +6909,15 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
for (node = snode->edittree->nodes.first; node; node = node->next) {
if (node->flag & NODE_SELECT && is_node_parent_select(node) == false) {
node->flag |= NODE_TRANSFORM;
- t->total++;
+ tc->data_len++;
}
else {
node->flag &= ~NODE_TRANSFORM;
}
}
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransNode TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransNode TransData2D");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransNode TransData2D");
for (node = snode->edittree->nodes.first; node; node = node->next) {
if (node->flag & NODE_TRANSFORM) {
@@ -6972,7 +7102,7 @@ static void planeTrackToTransData(const int framenr, TransData *td, TransData2D
}
}
-static void transDataTrackingFree(TransInfo *UNUSED(t), TransCustomData *custom_data)
+static void transDataTrackingFree(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
{
if (custom_data->data) {
TransDataTracking *tdt = custom_data->data;
@@ -6997,22 +7127,24 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
TransDataTracking *tdt;
int framenr = ED_space_clip_get_clip_frame_number(sc);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* count */
- t->total = 0;
+ tc->data_len = 0;
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- t->total++; /* offset */
+ tc->data_len++; /* offset */
if (track->flag & SELECT)
- t->total++;
+ tc->data_len++;
if (track->pat_flag & SELECT)
- t->total += 4;
+ tc->data_len += 4;
if (track->search_flag & SELECT)
- t->total += 2;
+ tc->data_len += 2;
}
track = track->next;
@@ -7023,18 +7155,18 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
plane_track = plane_track->next)
{
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- t->total += 4;
+ tc->data_len += 4;
}
}
- if (t->total == 0)
+ if (tc->data_len == 0)
return;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
- tdt = t->custom.type.data = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransTracking TransData2D");
+ tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking), "TransTracking TransDataTracking");
- t->custom.type.free_cb = transDataTrackingFree;
+ tc->custom.type.free_cb = transDataTrackingFree;
/* create actual data */
track = tracksbase->first;
@@ -7136,8 +7268,10 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* count */
- t->total = 0;
+ tc->data_len = 0;
if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
return;
@@ -7154,23 +7288,23 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
continue;
if (marker->flag & MARKER_GRAPH_SEL_X)
- t->total += 1;
+ tc->data_len += 1;
if (marker->flag & MARKER_GRAPH_SEL_Y)
- t->total += 1;
+ tc->data_len += 1;
}
}
track = track->next;
}
- if (t->total == 0)
+ if (tc->data_len == 0)
return;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
- t->custom.type.data = tdt = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
- t->custom.type.free_cb = transDataTrackingFree;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransTracking TransData2D");
+ tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTracking), "TransTracking TransDataTracking");
+ tc->custom.type.free_cb = transDataTrackingFree;
/* create actual data */
track = tracksbase->first;
@@ -7211,7 +7345,9 @@ static void createTransTrackingData(bContext *C, TransInfo *t)
MovieClip *clip = ED_space_clip_get_clip(sc);
int width, height;
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!clip)
return;
@@ -7232,12 +7368,14 @@ static void createTransTrackingData(bContext *C, TransInfo *t)
static void cancelTransTracking(TransInfo *t)
{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
SpaceClip *sc = t->sa->spacedata.first;
int i, framenr = ED_space_clip_get_clip_frame_number(sc);
- TransDataTracking *tdt_array = t->custom.type.data;
+ TransDataTracking *tdt_array = tc->custom.type.data;
+
i = 0;
- while (i < t->total) {
+ while (i < tc->data_len) {
TransDataTracking *tdt = &tdt_array[i];
if (tdt->mode == transDataTracking_ModeTracks) {
@@ -7294,8 +7432,10 @@ void flushTransTracking(TransInfo *t)
if (t->state == TRANS_CANCEL)
cancelTransTracking(t);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d, tdt = t->custom.type.data; a < t->total; a++, td2d++, td++, tdt++) {
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len; a++, td2d++, td++, tdt++) {
if (tdt->mode == transDataTracking_ModeTracks) {
float loc2d[2];
@@ -7561,7 +7701,9 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT);
float asp[2];
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!mask)
return;
@@ -7621,13 +7763,13 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- t->total = (is_prop_edit) ? count : countsel;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mask Editing)");
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransObData2D(Mask Editing)");
- t->custom.type.data = tdm = MEM_callocN(t->total * sizeof(TransDataMasking), "TransDataMasking(Mask Editing)");
- t->custom.type.use_free = true;
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(Mask Editing)");
+ tc->custom.type.data = tdm = MEM_callocN(tc->data_len * sizeof(TransDataMasking), "TransDataMasking(Mask Editing)");
+ tc->custom.type.use_free = true;
/* create data */
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
@@ -7684,12 +7826,14 @@ void flushTransMasking(TransInfo *t)
int a;
float asp[2], inv[2];
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
inv[0] = 1.0f / asp[0];
inv[1] = 1.0f / asp[1];
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data2d, tdm = t->custom.type.data; a < t->total; a++, td++, tdm++) {
+ for (a = 0, td = tc->data_2d, tdm = tc->custom.type.data; a < tc->data_len; a++, td++, tdm++) {
td->loc2d[0] = td->loc[0] * inv[0];
td->loc2d[1] = td->loc[1] * inv[1];
mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
@@ -7808,7 +7952,9 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
int i;
int total = 0;
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!paint || !paint->brush || !paint->brush->paint_curve)
return;
@@ -7834,11 +7980,11 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
if (!total)
return;
- t->total = total;
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D");
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransData");
- t->custom.type.data = tdpc = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
- t->custom.type.use_free = true;
+ tc->data_len = total;
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData");
+ tc->custom.type.data = tdpc = MEM_callocN(tc->data_len * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
+ tc->custom.type.use_free = true;
for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
if (PC_IS_ANY_SEL(pcp)) {
@@ -7869,10 +8015,13 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
void flushTransPaintCurve(TransInfo *t)
{
int i;
- TransData2D *td2d = t->data2d;
- TransDataPaintCurve *tdpc = t->custom.type.data;
- for (i = 0; i < t->total; i++, tdpc++, td2d++) {
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ TransData2D *td2d = tc->data_2d;
+ TransDataPaintCurve *tdpc = tc->custom.type.data;
+
+ for (i = 0; i < tc->data_len; i++, tdpc++, td2d++) {
PaintCurvePoint *pcp = tdpc->pcp;
copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
}
@@ -7891,15 +8040,16 @@ static void createTransGPencil(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
-
-
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* == Grease Pencil Strokes to Transform Data ==
* Grease Pencil stroke points can be a mixture of 2D (screen-space),
* or 3D coordinates. However, they're always saved as 3D points.
* For now, we just do these without creating TransData2D for the 2D
* strokes. This may cause issues in future though.
*/
- t->total = 0;
+ tc->data_len = 0;
if (gpd == NULL)
return;
@@ -7928,11 +8078,11 @@ static void createTransGPencil(bContext *C, TransInfo *t)
if (is_prop_edit_connected) {
/* connected only - so only if selected */
if (gps->flag & GP_STROKE_SELECT)
- t->total += gps->totpoints;
+ tc->data_len += gps->totpoints;
}
else {
/* everything goes - connection status doesn't matter */
- t->total += gps->totpoints;
+ tc->data_len += gps->totpoints;
}
}
else {
@@ -7944,7 +8094,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
// TODO: 2D vs 3D?
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT)
- t->total++;
+ tc->data_len++;
}
}
}
@@ -7953,13 +8103,13 @@ static void createTransGPencil(bContext *C, TransInfo *t)
}
/* Stop trying if nothing selected */
- if (t->total == 0) {
+ if (tc->data_len == 0) {
return;
}
/* Allocate memory for data */
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(GPencil)");
- td = t->data;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)");
+ td = tc->data;
unit_m3(smtx);
unit_m3(mtx);
@@ -8127,6 +8277,29 @@ static void createTransGPencil(bContext *C, TransInfo *t)
}
}
+static int countAndCleanTransDataContainer(TransInfo *t)
+{
+ BLI_assert(ELEM(t->data_len_all, 0, -1));
+ t->data_len_all = 0;
+ uint data_container_len_orig = t->data_container_len;
+ for (TransDataContainer *th_end = t->data_container - 1, *tc = t->data_container + (t->data_container_len - 1); tc != th_end; tc--) {
+ if (tc->data_len == 0) {
+ uint index = tc - t->data_container;
+ if (index + 1 != t->data_container_len) {
+ SWAP(TransDataContainer, t->data_container[index], t->data_container[t->data_container_len - 1]);
+ }
+ t->data_container_len -= 1;
+ }
+ else {
+ t->data_len_all += tc->data_len;
+ }
+ }
+ if (data_container_len_orig != t->data_container_len) {
+ t->data_container = MEM_reallocN(t->data_container, sizeof(*t->data_container) * t->data_container_len);
+ }
+ return t->data_len_all;
+}
+
void createTransData(bContext *C, TransInfo *t)
{
@@ -8134,16 +8307,27 @@ void createTransData(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
Object *ob = OBACT(view_layer);
+ t->data_len_all = -1;
+
/* if tests must match recalcData for correct updates */
if (t->options & CTX_TEXTURE) {
t->flag |= T_TEXTURE;
+
createTransTexspace(t);
+ countAndCleanTransDataContainer(t);
}
else if (t->options & CTX_EDGE) {
- t->ext = NULL;
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
t->flag |= T_EDIT;
+
createTransEdge(t);
- if (t->data && t->flag & T_PROP_EDIT) {
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8152,9 +8336,11 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->options & CTX_GPENCIL_STROKES) {
t->options |= CTX_GPENCIL_STROKES;
t->flag |= T_POINTS;
+
createTransGPencil(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8163,22 +8349,32 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IMAGE) {
t->flag |= T_POINTS | T_2D_EDIT;
if (t->options & CTX_MASK) {
+
/* copied from below */
createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, true);
sort_trans_data_dist(t);
}
}
else if (t->options & CTX_PAINT_CURVE) {
- if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN))
+ if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ }
}
- else if (t->obedit) {
+ else if (t->obedit_type == OB_MESH) {
+
+ initTransDataContainers_FromObjectData(t);
createTransUVs(C, t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ countAndCleanTransDataContainer(t);
+
+ t->flag |= T_EDIT;
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8187,9 +8383,11 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
+
createTransActionData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
//set_prop_dist(t, false); /* don't do that, distance has been set in createTransActionData already */
sort_trans_data_dist(t);
@@ -8198,17 +8396,20 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransNlaData(C, t);
+ countAndCleanTransDataContainer(t);
}
else if (t->spacetype == SPACE_SEQ) {
t->flag |= T_POINTS | T_2D_EDIT;
t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transformations */
createTransSeqData(C, t);
+ countAndCleanTransDataContainer(t);
}
else if (t->spacetype == SPACE_IPO) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransGraphEditData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, false); /* don't do that, distance has been set in createTransGraphEditData already */
sort_trans_data_dist(t);
@@ -8216,8 +8417,11 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;
+
createTransNodeData(C, t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8225,34 +8429,42 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_CLIP) {
t->flag |= T_POINTS | T_2D_EDIT;
- if (t->options & CTX_MOVIECLIP)
+ if (t->options & CTX_MOVIECLIP) {
createTransTrackingData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
else if (t->options & CTX_MASK) {
/* copied from above */
createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, true);
sort_trans_data_dist(t);
}
}
}
- else if (t->obedit) {
- t->ext = NULL;
- if (t->obedit->type == OB_MESH) {
+ else if (t->obedit_type != -1) {
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
+ if (t->obedit_type == OB_MESH) {
createTransEditVerts(t);
}
- else if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
+ else if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
createTransCurveVerts(t);
}
- else if (t->obedit->type == OB_LATTICE) {
+ else if (t->obedit_type == OB_LATTICE) {
createTransLatticeVerts(t);
}
- else if (t->obedit->type == OB_MBALL) {
+ else if (t->obedit_type == OB_MBALL) {
createTransMBallVerts(t);
}
- else if (t->obedit->type == OB_ARMATURE) {
+ else if (t->obedit_type == OB_ARMATURE) {
t->flag &= ~T_PROP_EDIT;
createTransArmatureVerts(t);
}
@@ -8260,12 +8472,14 @@ void createTransData(bContext *C, TransInfo *t)
printf("edit type not implemented!\n");
}
+ countAndCleanTransDataContainer(t);
+
t->flag |= T_EDIT | T_POINTS;
- if (t->data && t->flag & T_PROP_EDIT) {
- if (ELEM(t->obedit->type, OB_CURVE, OB_MESH)) {
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) {
sort_trans_data(t); // makes selected become first in array
- if ((t->obedit->type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
+ if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
/* already calculated by editmesh_set_connectivity_distance */
}
else {
@@ -8284,13 +8498,21 @@ void createTransData(bContext *C, TransInfo *t)
if (t->mode == TFM_BONESIZE) {
t->flag &= ~(T_EDIT | T_POINTS);
t->flag |= T_POSE;
- t->poseobj = ob; /* <- tsk tsk, this is going to give issues one day */
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->poseobj = tc->obedit;
+ tc->obedit = NULL;
+ }
}
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
// XXX this is currently limited to active armature only...
// XXX active-layer checking isn't done as that should probably be checked through context instead
- createTransPose(t, ob);
+
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t);
+ createTransPose(t, NULL, 0);
+ countAndCleanTransDataContainer(t);
}
else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
/* important that ob_armature can be set even when its not selected [#23412]
@@ -8300,7 +8522,11 @@ void createTransData(bContext *C, TransInfo *t)
Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
if (base_arm) {
if (BASE_VISIBLE(base_arm)) {
- createTransPose(t, ob_armature);
+ Object *objects[1];
+ objects[0] = ob_armature;
+ uint objects_len = 1;
+ createTransPose(t, objects, objects_len);
+ countAndCleanTransDataContainer(t);
}
}
@@ -8308,9 +8534,10 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
createTransParticleVerts(C, t);
+ countAndCleanTransDataContainer(t);
t->flag |= T_POINTS;
- if (t->data && t->flag & T_PROP_EDIT) {
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8320,13 +8547,15 @@ void createTransData(bContext *C, TransInfo *t)
if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
}
}
else {
createTransObject(C, t);
+ countAndCleanTransDataContainer(t);
t->flag |= T_OBJECT;
- if (t->data && t->flag & T_PROP_EDIT) {
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
// selected objects are already first, no need to presort
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8344,4 +8573,7 @@ void createTransData(bContext *C, TransInfo *t)
}
}
}
+
+ /* Check that 'countAndCleanTransDataContainer' ran. */
+ BLI_assert(t->data_len_all != -1);
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 08e8e8fe175..2ab6d0d0900 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -82,6 +82,7 @@
#include "BKE_tracking.h"
#include "BKE_mask.h"
#include "BKE_workspace.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -127,8 +128,10 @@ void getViewVector(TransInfo *t, float coord[3], float vec[3])
/* ************************** GENERICS **************************** */
-static void clipMirrorModifier(TransInfo *t, Object *ob)
+static void clipMirrorModifier(TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->obedit;
ModifierData *md = ob->modifiers.first;
float tolerance[3] = {0.0f, 0.0f, 0.0f};
int axis = 0;
@@ -154,7 +157,6 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
if (axis) {
float mtx[4][4], imtx[4][4];
int i;
- TransData *td = t->data;
if (mmd->mirror_ob) {
float obinv[4][4];
@@ -164,7 +166,8 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
invert_m4_m4(imtx, mtx);
}
- for (i = 0; i < t->total; i++, td++) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
int clip;
float loc[3], iloc[3];
@@ -222,16 +225,18 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
}
}
}
+ }
}
/* assumes obedit set to mesh object */
static void editbmesh_apply_to_mirror(TransInfo *t)
{
- TransData *td = t->data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
BMVert *eve;
int i;
-
- for (i = 0; i < t->total; i++, td++) {
+
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->loc == NULL)
@@ -250,6 +255,7 @@ static void editbmesh_apply_to_mirror(TransInfo *t)
td->loc[0] = 0;
}
}
+ }
}
/* for the realtime animation recording feature, handle overlapping data */
@@ -432,12 +438,14 @@ static void recalcData_nla(TransInfo *t)
Scene *scene = t->scene;
double secf = FPS;
int i;
-
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* for each strip we've got, perform some additional validation of the values that got set before
* using RNA to set the value (which does some special operations when setting these values to make
* sure that everything works ok)
*/
- for (i = 0; i < t->total; i++, tdn++) {
+ for (i = 0; i < tc->data_len; i++, tdn++) {
NlaStrip *strip = tdn->strip;
PointerRNA strip_ptr;
short pExceeded, nExceeded, iter;
@@ -654,14 +662,18 @@ static void recalcData_image(TransInfo *t)
else if (t->options & CTX_PAINT_CURVE) {
flushTransPaintCurve(t);
}
- else if (t->obedit && t->obedit->type == OB_MESH) {
+ else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
SpaceImage *sima = t->sa->spacedata.first;
flushTransUVs(t);
if (sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_re_solve();
-
- DEG_id_tag_update(t->obedit->data, 0);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len) {
+ DEG_id_tag_update(tc->obedit->data, 0);
+ }
+ }
}
}
@@ -716,19 +728,21 @@ static void recalcData_objects(TransInfo *t)
{
Base *base = t->view_layer->basact;
- if (t->obedit) {
- if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
- Curve *cu = t->obedit->data;
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- Nurb *nu = nurbs->first;
-
+ if (t->obedit_type != -1) {
+ if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
+
if (t->state != TRANS_CANCEL) {
- clipMirrorModifier(t, t->obedit);
+ clipMirrorModifier(t);
applyProject(t);
}
-
- DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
-
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Curve *cu = tc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ Nurb *nu = nurbs->first;
+
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+
if (t->state == TRANS_CANCEL) {
while (nu) {
BKE_nurb_handles_calc(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
@@ -743,25 +757,28 @@ static void recalcData_objects(TransInfo *t)
nu = nu->next;
}
}
+ }
}
- else if (t->obedit->type == OB_LATTICE) {
- Lattice *la = t->obedit->data;
-
+ else if (t->obedit_type == OB_LATTICE) {
+
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
-
- DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
-
- if (la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Lattice *la = tc->obedit->data;
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ if (la->editlatt->latt->flag & LT_OUTSIDE) {
+ outside_lattice(la->editlatt->latt);
+ }
+ }
}
- else if (t->obedit->type == OB_MESH) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ else if (t->obedit_type == OB_MESH) {
/* mirror modifier clipping? */
if (t->state != TRANS_CANCEL) {
/* apply clipping after so we never project past the clip plane [#25423] */
applyProject(t);
- clipMirrorModifier(t, t->obedit);
+ clipMirrorModifier(t);
}
if ((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
editbmesh_apply_to_mirror(t);
@@ -773,26 +790,30 @@ static void recalcData_objects(TransInfo *t)
projectVertSlideData(t, false);
}
- DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
-
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
EDBM_mesh_normals_update(em);
BKE_editmesh_tessface_calc(em);
+ }
}
- else if (t->obedit->type == OB_ARMATURE) { /* no recalc flag, does pose */
- bArmature *arm = t->obedit->data;
- ListBase *edbo = arm->edbo;
- EditBone *ebo, *ebo_parent;
- TransData *td = t->data;
- int i;
-
+ else if (t->obedit_type == OB_ARMATURE) { /* no recalc flag, does pose */
+
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
-
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ EditBone *ebo, *ebo_parent;
+ TransData *td = tc->data;
+ int i;
+
/* Ensure all bones are correctly adjusted */
for (ebo = edbo->first; ebo; ebo = ebo->next) {
ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
-
+
if (ebo_parent) {
/* If this bone has a parent tip that has been moved */
if (ebo_parent->flag & BONE_TIPSEL) {
@@ -832,7 +853,7 @@ static void recalcData_objects(TransInfo *t)
if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
/* fix roll */
- for (i = 0; i < t->total; i++, td++) {
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->extra) {
float vec[3], up_axis[3];
float qrot[4];
@@ -859,23 +880,32 @@ static void recalcData_objects(TransInfo *t)
}
}
}
-
+
if (arm->flag & ARM_MIRROR_EDIT) {
- if (t->state != TRANS_CANCEL)
- ED_armature_edit_transform_mirror_update(t->obedit);
- else
- restoreBones(t);
+ if (t->state != TRANS_CANCEL) {
+ ED_armature_edit_transform_mirror_update(tc->obedit);
+ }
+ else {
+ restoreBones(tc);
+ }
+ }
}
}
else {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
- DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len) {
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ }
+ }
}
+
}
- else if ((t->flag & T_POSE) && t->poseobj) {
- Object *ob = t->poseobj;
+ else if (t->flag & T_POSE) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
bArmature *arm = ob->data;
/* if animtimer is running, and the object already has animation data,
@@ -900,6 +930,7 @@ static void recalcData_objects(TransInfo *t)
}
else
BKE_pose_where_is(&t->eval_ctx, t->scene, ob);
+ }
}
else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
PE_get_current(t->scene, base->object))
@@ -915,9 +946,11 @@ static void recalcData_objects(TransInfo *t)
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
-
- for (i = 0; i < t->total; i++) {
- TransData *td = t->data + i;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+
+ for (i = 0; i < tc->data_len; i++, td++) {
Object *ob = td->ob;
if (td->flag & TD_NOACTION)
@@ -944,6 +977,7 @@ static void recalcData_objects(TransInfo *t)
if (t->flag & T_TEXTURE)
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
+ }
}
}
@@ -954,7 +988,9 @@ static void recalcData_sequencer(TransInfo *t)
int a;
Sequence *seq_prev = NULL;
- for (a = 0, td = t->data; a < t->total; a++, td++) {
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
TransDataSeq *tdsq = (TransDataSeq *) td->extra;
Sequence *seq = tdsq->seq;
@@ -979,8 +1015,10 @@ static void recalcData_sequencer(TransInfo *t)
/* force recalculation of triangles during transformation */
static void recalcData_gpencil_strokes(TransInfo *t)
{
- TransData *td = t->data;
- for (int i = 0; i < t->total; i++, td++) {
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
bGPDstroke *gps = td->extra;
if (gps != NULL) {
gps->flag |= GP_STROKE_RECALC_CACHES;
@@ -1078,11 +1116,17 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
*/
void resetTransModal(TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (t->mode == TFM_EDGE_SLIDE) {
- freeEdgeSlideVerts(t, &t->custom.mode);
+ freeEdgeSlideVerts(t, tc, &tc->custom.mode);
}
else if (t->mode == TFM_VERT_SLIDE) {
- freeVertSlideVerts(t, &t->custom.mode);
+ freeVertSlideVerts(t, tc, &tc->custom.mode);
+ }
+ else {
+ /* no need to keep looping... */
+ break;
+ }
}
}
@@ -1105,6 +1149,40 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
}
}
+void initTransDataContainers_FromObjectData(TransInfo *t)
+{
+ const eObjectMode object_mode = OBACT(t->view_layer) ? OBACT(t->view_layer)->mode : OB_MODE_OBJECT;
+ const short object_type = OBACT(t->view_layer) ? OBACT(t->view_layer)->type : -1;
+
+ if ((object_mode & OB_MODE_EDIT) ||
+ ((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE)))
+ {
+ if (t->data_container) {
+ MEM_freeN(t->data_container);
+ }
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode(
+ t->view_layer, &objects_len, {
+ .object_mode = object_mode,
+ .no_dup_data = true});
+ t->data_container = MEM_callocN(sizeof(*t->data_container) * objects_len, __func__);
+ t->data_container_len = objects_len;
+
+ for (int i = 0; i < objects_len; i++) {
+ TransDataContainer *tc = &t->data_container[i];
+ if (object_mode & OB_MODE_EDIT) {
+ tc->obedit = objects[i];
+ copy_m3_m4(tc->obedit_mat, tc->obedit->obmat);
+ normalize_m3(tc->obedit_mat);
+ }
+ else if (object_mode & OB_MODE_POSE) {
+ tc->poseobj = objects[i];
+ }
+ }
+ MEM_freeN(objects);
+ }
+}
+
/**
* Setup internal data, mouse, vectors
*
@@ -1118,11 +1196,12 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *sce = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
+ const eObjectMode object_mode = OBACT(view_layer) ? OBACT(view_layer)->mode : OB_MODE_OBJECT;
+ const short object_type = OBACT(view_layer) ? OBACT(view_layer)->type : -1;
ToolSettings *ts = CTX_data_tool_settings(C);
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
- Object *obedit = CTX_data_edit_object(C);
- Object *ob = CTX_data_active_object(C);
+
bGPdata *gpd = CTX_data_gpencil_data(C);
RenderEngineType *engine_type = CTX_data_engine_type(C);
PropertyRNA *prop;
@@ -1133,22 +1212,21 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->engine_type = engine_type;
t->sa = sa;
t->ar = ar;
- t->obedit = obedit;
t->settings = ts;
t->reports = op ? op->reports : NULL;
- if (obedit) {
- copy_m3_m4(t->obedit_mat, obedit->obmat);
- normalize_m3(t->obedit_mat);
- }
-
- t->data = NULL;
- t->ext = NULL;
-
t->helpline = HLP_NONE;
t->flag = 0;
-
+
+ t->obedit_type = (object_mode == OB_MODE_EDIT) ? object_type : -1;
+
+ /* Many kinds of transform only use a single handle. */
+ if (t->data_container == NULL) {
+ t->data_container = MEM_callocN(sizeof(*t->data_container), __func__);
+ t->data_container_len = 1;
+ }
+
t->redraw = TREDRAW_HARD; /* redraw first time */
if (event) {
@@ -1169,12 +1247,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->transform = NULL;
t->handleEvent = NULL;
- t->total = 0;
+ t->data_len_all = 0;
t->val = 0.0f;
zero_v3(t->vec);
- zero_v3(t->center);
zero_v3(t->center_global);
unit_m3(t->mat);
@@ -1260,13 +1337,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
const bool use_island = transdata_check_local_islands(t, t->around);
- if (obedit && !use_island) {
+ if ((t->obedit_type != -1) && !use_island) {
t->options |= CTX_NO_PET;
}
}
}
- if (ob && ob->mode & OB_MODE_ALL_PAINT) {
+ if (object_mode & OB_MODE_ALL_PAINT) {
Paint *p = BKE_paint_get_active_from_context(C);
if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
t->options |= CTX_PAINT_CURVE;
@@ -1295,7 +1372,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->view = &ar->v2d;
t->around = sima->around;
- if (ED_space_image_show_uvedit(sima, t->obedit)) {
+ if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
/* UV transform */
}
else if (sima->mode == SI_MODE_MASK) {
@@ -1385,7 +1462,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
// Need stuff to take it from edit mesh or whatnot here
else if (t->spacetype == SPACE_VIEW3D) {
- if (t->obedit && t->obedit->type == OB_MESH && (((Mesh *)t->obedit->data)->editflag & ME_EDIT_MIRROR_X)) {
+ /* TODO(campbell): xform, get mirror from each object. */
+ if (t->obedit_type == OB_MESH && (((Mesh *)OBACT(t->view_layer)->data)->editflag & ME_EDIT_MIRROR_X)) {
t->flag |= T_MIRROR;
t->mirror = 1;
}
@@ -1406,7 +1484,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
else if (t->spacetype == SPACE_ACTION) {
t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
}
- else if (t->obedit) {
+ else if (t->obedit_type != -1) {
t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
}
else if (t->options & CTX_GPENCIL_STROKES) {
@@ -1421,7 +1499,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
}
- else if (t->obedit == NULL && ts->proportional_objects) {
+ else if ((t->obedit_type == -1) && ts->proportional_objects) {
t->flag |= T_PROP_EDIT;
}
}
@@ -1467,8 +1545,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
setTransformViewAspect(t, t->aspect);
if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_get_array(op->ptr, prop, t->center);
- mul_v3_v3(t->center, t->aspect);
+ RNA_property_float_get_array(op->ptr, prop, t->center_global);
+ mul_v3_v3(t->center_global, t->aspect);
t->flag |= T_OVERRIDE_CENTER;
}
@@ -1476,11 +1554,25 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initNumInput(&t->num);
}
+static void freeTransCustomDataContainer(TransInfo *t, TransDataContainer *tc, TransCustomDataContainer *tcdc)
+{
+ TransCustomData *custom_data = &tcdc->first_elem;
+ for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
+ if (custom_data->free_cb) {
+ /* Can take over freeing t->data and data_2d etc... */
+ custom_data->free_cb(t, tc, custom_data);
+ BLI_assert(custom_data->data == NULL);
+ }
+ else if ((custom_data->data != NULL) && custom_data->use_free) {
+ MEM_freeN(custom_data->data);
+ custom_data->data = NULL;
+ }
+ }
+}
+
/* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
void postTrans(bContext *C, TransInfo *t)
{
- TransData *td;
-
if (t->draw_handle_view)
ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
if (t->draw_handle_apply)
@@ -1491,46 +1583,37 @@ void postTrans(bContext *C, TransInfo *t)
WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
/* Free all custom-data */
- {
- TransCustomData *custom_data = &t->custom.first_elem;
- for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
- if (custom_data->free_cb) {
- /* Can take over freeing t->data and data2d etc... */
- custom_data->free_cb(t, custom_data);
- BLI_assert(custom_data->data == NULL);
- }
- else if ((custom_data->data != NULL) && custom_data->use_free) {
- MEM_freeN(custom_data->data);
- custom_data->data = NULL;
- }
- }
+ freeTransCustomDataContainer(t, NULL, &t->custom);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ freeTransCustomDataContainer(t, tc, &tc->custom);
}
/* postTrans can be called when nothing is selected, so data is NULL already */
- if (t->data) {
-
- /* free data malloced per trans-data */
- if ((t->obedit && ELEM(t->obedit->type, OB_CURVE, OB_SURF)) ||
- (t->spacetype == SPACE_IPO))
- {
- int a;
- for (a = 0, td = t->data; a < t->total; a++, td++) {
- if (td->flag & TD_BEZTRIPLE) {
- MEM_freeN(td->hdata);
+ if (t->data_len_all != 0) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ /* free data malloced per trans-data */
+ if (ELEM(t->obedit_type, OB_CURVE, OB_SURF) ||
+ (t->spacetype == SPACE_IPO))
+ {
+ TransData *td = tc->data;
+ for (int a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_BEZTRIPLE) {
+ MEM_freeN(td->hdata);
+ }
}
}
+ MEM_freeN(tc->data);
+
+ MEM_SAFE_FREE(tc->data_ext);
+ MEM_SAFE_FREE(tc->data_2d);
}
- MEM_freeN(t->data);
}
+ MEM_SAFE_FREE(t->data_container);
+ t->data_container = NULL;
+
BLI_freelistN(&t->tsnap.points);
- if (t->ext) MEM_freeN(t->ext);
- if (t->data2d) {
- MEM_freeN(t->data2d);
- t->data2d = NULL;
- }
-
if (t->spacetype == SPACE_IMAGE) {
if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
/* pass */
@@ -1558,9 +1641,11 @@ void postTrans(bContext *C, TransInfo *t)
void applyTransObjects(TransInfo *t)
{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
TransData *td;
-
- for (td = t->data; td < t->data + t->total; td++) {
+
+ for (td = tc->data; td < tc->data + tc->data_len; td++) {
copy_v3_v3(td->iloc, td->loc);
if (td->ext->rot) {
copy_v3_v3(td->ext->irot, td->ext->rot);
@@ -1609,14 +1694,16 @@ static void restoreElement(TransData *td)
void restoreTransObjects(TransInfo *t)
{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
TransData *td;
TransData2D *td2d;
- for (td = t->data; td < t->data + t->total; td++) {
+ for (td = tc->data; td < tc->data + tc->data_len; td++) {
restoreElement(td);
}
- for (td2d = t->data2d; t->data2d && td2d < t->data2d + t->total; td2d++) {
+ for (td2d = tc->data_2d; tc->data_2d && td2d < tc->data_2d + tc->data_len; td2d++) {
if (td2d->h1) {
td2d->h1[0] = td2d->ih1[0];
td2d->h1[1] = td2d->ih1[1];
@@ -1628,6 +1715,8 @@ void restoreTransObjects(TransInfo *t)
}
unit_m3(t->mat);
+
+ }
recalcData(t);
}
@@ -1635,32 +1724,26 @@ void restoreTransObjects(TransInfo *t)
void calculateCenter2D(TransInfo *t)
{
BLI_assert(!is_zero_v3(t->aspect));
-
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- float vec[3];
-
- copy_v3_v3(vec, t->center);
- mul_m4_v3(ob->obmat, vec);
- projectFloatView(t, vec, t->center2d);
- }
- else {
- projectFloatView(t, t->center, t->center2d);
- }
+ projectFloatView(t, t->center_global, t->center2d);
}
-void calculateCenterGlobal(
- TransInfo *t, const float center_local[3],
- float r_center_global[3])
+void calculateCenterLocal(
+ TransInfo *t, const float center_global[3])
{
/* setting constraint center */
/* note, init functions may over-ride t->center */
if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_v3_m4v3(r_center_global, ob->obmat, center_local);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ float obinv[4][4];
+ Object *ob = tc->obedit ? tc->obedit : tc->poseobj;
+ invert_m4_m4(obinv, ob->obmat);
+ mul_v3_m4v3(tc->center_local, obinv, center_global);
+ }
}
else {
- copy_v3_v3(r_center_global, center_local);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ copy_v3_v3(tc->center_local, center_global);
+ }
}
}
@@ -1672,16 +1755,7 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
copy_v3_v3(r_center, cursor);
/* If edit or pose mode, move cursor in local space */
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- float mat[3][3], imat[3][3];
-
- sub_v3_v3v3(r_center, r_center, ob->obmat[3]);
- copy_m3_m4(mat, ob->obmat);
- invert_m3_m3(imat, mat);
- mul_m3_v3(imat, r_center);
- }
- else if (t->options & CTX_PAINT_CURVE) {
+ if (t->options & CTX_PAINT_CURVE) {
if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
r_center[0] = t->ar->winx / 2.0f;
r_center[1] = t->ar->winy / 2.0f;
@@ -1755,16 +1829,26 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
{
float partial[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob_xform = tc->obedit ? tc->obedit : tc->poseobj;
int i;
-
- for (i = 0; i < t->total; i++) {
- if (t->data[i].flag & TD_SELECTED) {
- if (!(t->data[i].flag & TD_NOCENTER)) {
- add_v3_v3(partial, t->data[i].center);
+ for (i = 0; i < tc->data_len; i++) {
+ if (tc->data[i].flag & TD_SELECTED) {
+ if (!(tc->data[i].flag & TD_NOCENTER)) {
+ if (ob_xform) {
+ float v[3];
+ mul_v3_m4v3(v, ob_xform->obmat, tc->data[i].center);
+ add_v3_v3(partial, v);
+ }
+ else {
+ add_v3_v3(partial, tc->data[i].center);
+ }
total++;
}
}
}
+ }
if (total) {
mul_v3_fl(partial, 1.0f / (float)total);
}
@@ -1776,18 +1860,31 @@ void calculateCenterBound(TransInfo *t, float r_center[3])
float max[3];
float min[3];
int i;
- for (i = 0; i < t->total; i++) {
- if (i) {
- if (t->data[i].flag & TD_SELECTED) {
- if (!(t->data[i].flag & TD_NOCENTER))
- minmax_v3v3_v3(min, max, t->data[i].center);
+ bool is_first = true;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob_xform = tc->obedit ? tc->obedit : tc->poseobj;
+ for (i = 0; i < tc->data_len; i++) {
+ if (is_first == false) {
+ if (tc->data[i].flag & TD_SELECTED) {
+ if (!(tc->data[i].flag & TD_NOCENTER)) {
+ if (ob_xform) {
+ float v[3];
+ mul_v3_m4v3(v, ob_xform->obmat, tc->data[i].center);
+ minmax_v3v3_v3(min, max, v);
+ }
+ else {
+ minmax_v3v3_v3(min, max, tc->data[i].center);
+ }
+ }
}
+ is_first = false;
}
else {
- copy_v3_v3(max, t->data[i].center);
- copy_v3_v3(min, t->data[i].center);
+ copy_v3_v3(max, tc->data[i].center);
+ copy_v3_v3(min, tc->data[i].center);
}
}
+ }
mid_v3_v3v3(r_center, min, max);
}
@@ -1796,10 +1893,13 @@ void calculateCenterBound(TransInfo *t, float r_center[3])
*/
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+
bool ok = false;
- if (t->obedit) {
- if (ED_object_editmode_calc_active_center(t->obedit, select_only, r_center)) {
+ if (tc->obedit) {
+ if (ED_object_editmode_calc_active_center(tc->obedit, select_only, r_center)) {
+ mul_m4_v3(tc->obedit->obmat, r_center);
ok = true;
}
}
@@ -1810,6 +1910,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
bPoseChannel *pchan = BKE_pose_channel_active(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
copy_v3_v3(r_center, pchan->pose_head);
+ mul_m4_v3(tc->obedit->obmat, r_center);
ok = true;
}
}
@@ -1874,14 +1975,13 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
void calculateCenter(TransInfo *t)
{
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- calculateCenter_FromAround(t, t->around, t->center);
+ calculateCenter_FromAround(t, t->around, t->center_global);
}
- calculateCenterGlobal(t, t->center, t->center_global);
+ calculateCenterLocal(t, t->center_global);
/* avoid calculating again */
{
TransCenterData *cd = &t->center_cache[t->around];
- copy_v3_v3(cd->local, t->center);
copy_v3_v3(cd->global, t->center_global);
cd->is_set = true;
}
@@ -1899,16 +1999,15 @@ void calculateCenter(TransInfo *t)
normalize_v3(axis);
/* 6.0 = 6 grid units */
- axis[0] = t->center[0] - 6.0f * axis[0];
- axis[1] = t->center[1] - 6.0f * axis[1];
- axis[2] = t->center[2] - 6.0f * axis[2];
+ axis[0] = t->center_global[0] - 6.0f * axis[0];
+ axis[1] = t->center_global[1] - 6.0f * axis[1];
+ axis[2] = t->center_global[2] - 6.0f * axis[2];
projectFloatView(t, axis, t->center2d);
/* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
if (t->mode == TFM_TRANSLATION) {
- copy_v3_v3(t->center, axis);
- copy_v3_v3(t->center_global, t->center);
+ copy_v3_v3(t->center_global, axis);
}
}
}
@@ -1942,8 +2041,7 @@ const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
BLI_assert(around <= V3D_AROUND_ACTIVE);
TransCenterData *cd = &t->center_cache[around];
if (cd->is_set == false) {
- calculateCenter_FromAround(t, around, cd->local);
- calculateCenterGlobal(t, cd->local, cd->global);
+ calculateCenter_FromAround(t, around, cd->global);
cd->is_set = true;
}
return cd;
@@ -1951,7 +2049,6 @@ const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
void calculatePropRatio(TransInfo *t)
{
- TransData *td = t->data;
int i;
float dist;
const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
@@ -1960,7 +2057,9 @@ void calculatePropRatio(TransInfo *t)
if (t->flag & T_PROP_EDIT) {
const char *pet_id = NULL;
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_SELECTED) {
td->factor = 1.0f;
}
@@ -2029,6 +2128,8 @@ void calculatePropRatio(TransInfo *t)
}
}
}
+ }
+
switch (t->prop_mode) {
case PROP_SHARP:
pet_id = N_("(Sharp)");
@@ -2063,8 +2164,11 @@ void calculatePropRatio(TransInfo *t)
}
}
else {
- for (i = 0; i < t->total; i++, td++) {
- td->factor = 1.0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ td->factor = 1.0;
+ }
}
}
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 5cb3f262ced..f128b903183 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -272,17 +272,19 @@ void applyProject(TransInfo *t)
{
/* XXX FLICKER IN OBJECT MODE */
if ((t->tsnap.project) && activeSnap(t) && (t->flag & T_NO_PROJECT) == 0) {
- TransData *td = t->data;
float tvec[3];
- float imat[4][4];
int i;
-
+
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td = tc->data;
+
+ float imat[4][4];
if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
+ Object *ob = tc->obedit ? tc->obedit : tc->poseobj;
invert_m4_m4(imat, ob->obmat);
}
- for (i = 0; i < t->total; i++, td++) {
+ for (i = 0; i < tc->data_len; i++, td++) {
float iloc[3], loc[3], no[3];
float mval_fl[2];
float dist_px = TRANSFORM_DIST_MAX_PX;
@@ -298,7 +300,7 @@ void applyProject(TransInfo *t)
copy_v3_v3(iloc, td->loc);
if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
+ Object *ob = tc->obedit ? tc->obedit : tc->poseobj;
mul_m4_v3(ob->obmat, iloc);
}
else if (t->flag & T_OBJECT) {
@@ -340,6 +342,7 @@ void applyProject(TransInfo *t)
//XXX constraintTransLim(t, td);
}
+ }
}
}
@@ -347,7 +350,6 @@ void applyGridAbsolute(TransInfo *t)
{
float grid_size = 0.0f;
GearsType grid_action;
- TransData *td;
float (*obmat)[4] = NULL;
bool use_obmat = false;
int i;
@@ -368,13 +370,16 @@ void applyGridAbsolute(TransInfo *t)
if (grid_size == 0.0f)
return;
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td;
+
if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
+ Object *ob = tc->obedit ? tc->obedit : tc->poseobj;
obmat = ob->obmat;
use_obmat = true;
}
- for (i = 0, td = t->data; i < t->total; i++, td++) {
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
float iloc[3], loc[3], tvec[3];
if (td->flag & TD_NOACTION)
@@ -405,6 +410,7 @@ void applyGridAbsolute(TransInfo *t)
mul_m3_v3(td->smtx, tvec);
add_v3_v3(td->loc, tvec);
}
+ }
}
void applySnapping(TransInfo *t, float *vec)
@@ -501,7 +507,8 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
static void initSnappingMode(TransInfo *t)
{
ToolSettings *ts = t->settings;
- Object *obedit = t->obedit;
+ /* All obedit types will match. */
+ const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1;
ViewLayer *view_layer = t->view_layer;
Base *base_act = view_layer->basact;
@@ -532,10 +539,10 @@ static void initSnappingMode(TransInfo *t)
/* Edit mode */
if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
+ ((obedit_type != -1) && ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
{
/* Exclude editmesh if using proportional edit */
- if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
+ if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
}
else {
@@ -544,13 +551,13 @@ static void initSnappingMode(TransInfo *t)
}
/* Particles edit mode*/
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit == NULL && base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT))
+ ((obedit_type == -1) && base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT))
{
t->tsnap.modeSelect = SNAP_ALL;
}
/* Object mode */
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit == NULL) ) // Object Mode
+ (obedit_type == -1) ) // Object Mode
{
/* In "Edit Strokes" mode, Snap tool can perform snap to selected or active objects (see T49632)
* TODO: perform self snap in gpencil_strokes */
@@ -863,7 +870,8 @@ static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const f
return len_squared_v3v3(p1, p2);
}
-static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
+static float RotationBetween(
+ TransInfo *t, const float p1[3], const float p2[3])
{
float angle, start[3], end[3];
@@ -874,7 +882,7 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
float axis[3], tmp[3];
- t->con.applyRot(t, NULL, axis, NULL);
+ t->con.applyRot(t, NULL, NULL, axis, NULL);
project_v3_v3v3(tmp, end, axis);
sub_v3_v3v3(end, end, tmp);
@@ -977,14 +985,14 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
t->tsnap.status &= ~POINT_INIT;
}
}
- else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) {
+ else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
/* same as above but for UV's */
Image *ima = ED_space_image(t->sa->spacedata.first);
float co[2];
UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
- if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) {
+ if (ED_uvedit_nearest_uv(t->scene, TRANS_DATA_CONTAINER_FIRST_EVIL(t)->obedit, ima, co, t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
t->tsnap.snapPoint[1] *= t->aspect[1];
@@ -1059,11 +1067,6 @@ static void TargetSnapActive(TransInfo *t)
/* Only need to calculate once */
if ((t->tsnap.status & TARGET_INIT) == 0) {
if (calculateCenterActive(t, true, t->tsnap.snapTarget)) {
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
- }
-
TargetSnapOffset(t, NULL);
t->tsnap.status |= TARGET_INIT;
@@ -1081,23 +1084,34 @@ static void TargetSnapMedian(TransInfo *t)
{
// Only need to calculate once
if ((t->tsnap.status & TARGET_INIT) == 0) {
- TransData *td = NULL;
- int i;
+ int i_accum = 0;
t->tsnap.snapTarget[0] = 0;
t->tsnap.snapTarget[1] = 0;
t->tsnap.snapTarget[2] = 0;
-
- for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
- add_v3_v3(t->tsnap.snapTarget, td->center);
- }
-
- mul_v3_fl(t->tsnap.snapTarget, 1.0 / i);
-
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob_xform = NULL;
+ if (t->flag & (T_EDIT | T_POSE)) {
+ ob_xform = tc->obedit ? tc->obedit : tc->poseobj;
+ }
+ TransData *td = tc->data;
+ int i;
+ for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
+ /* TODO(campbell): perform the global transformation once per TransDataContainer */
+ if (ob_xform) {
+ float v[3];
+ mul_v3_m4v3(v, ob_xform->obmat, td->center);
+ add_v3_v3(t->tsnap.snapTarget, v);
+ }
+ else {
+ add_v3_v3(t->tsnap.snapTarget, td->center);
+ }
+ }
+ i_accum += i;
}
+
+ mul_v3_fl(t->tsnap.snapTarget, 1.0 / i_accum);
TargetSnapOffset(t, NULL);
@@ -1110,12 +1124,14 @@ static void TargetSnapClosest(TransInfo *t)
// Only valid if a snap point has been selected
if (t->tsnap.status & POINT_INIT) {
float dist_closest = 0.0f;
- TransData *closest = NULL, *td = NULL;
+ TransData *closest = NULL;
/* Object mode */
if (t->flag & T_OBJECT) {
int i;
- for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td = tc->data;
+ for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
struct BoundBox *bb = BKE_object_boundbox_get(td->ob);
/* use boundbox if possible */
@@ -1157,17 +1173,20 @@ static void TargetSnapClosest(TransInfo *t)
}
}
}
+ }
}
else {
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td = tc->data;
int i;
- for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
+ for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
float loc[3];
float dist;
copy_v3_v3(loc, td->center);
if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
+ Object *ob = tc->obedit ? tc->obedit : tc->poseobj;
mul_m4_v3(ob->obmat, loc);
}
@@ -1181,6 +1200,7 @@ static void TargetSnapClosest(TransInfo *t)
dist_closest = dist;
}
}
+ }
}
TargetSnapOffset(t, closest);
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index d8b194e3336..0b77006afb7 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -36,6 +36,7 @@
#include "CLG_log.h"
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
#include "BLI_utildefines.h"
@@ -46,6 +47,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
#include "ED_gpencil.h"
@@ -495,3 +497,24 @@ void ED_OT_undo_history(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Undo Helper Functions
+ * \{ */
+
+void ED_undo_object_set_active_or_warn(ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
+{
+ Object *ob_prev = OBACT(view_layer);
+ if (ob_prev != ob) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base != NULL) {
+ view_layer->basact = base;
+ }
+ else {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_WARN(log, "'%s' failed to restore active object: '%s'", info, ob->id.name + 2);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 3fcc89d0973..328ab3f1a8d 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -51,6 +51,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
#include "BKE_material.h"
+#include "BKE_layer.h"
#include "BKE_scene.h"
@@ -1100,12 +1101,21 @@ void ED_uvedit_draw_main(
draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow);
if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
- if (show_uvshadow)
+ if (show_uvshadow) {
draw_uvs_shadow(obedit);
- else if (show_uvedit)
- draw_uvs(sima, scene, view_layer, obedit, depsgraph);
- else
+ }
+ else if (show_uvedit) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ draw_uvs(sima, scene, view_layer, ob_iter, depsgraph);
+ }
+ MEM_SAFE_FREE(objects);
+ }
+ else {
draw_uvs_texpaint(sima, scene, view_layer, obact);
+ }
if (show_uvedit && !(toolsettings->use_uv_sculpt))
ED_image_draw_cursor(ar, sima->cursor);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index c5f16d6fb14..e3db0162f10 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -51,6 +51,8 @@ void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off
/* find nearest */
typedef struct UvNearestHit {
+ /** Only for `*_multi(..)` versions of functions. */
+ struct Object *ob;
/** Always set if we have a hit. */
struct BMFace *efa;
struct BMLoop *l;
@@ -66,14 +68,23 @@ typedef struct UvNearestHit {
bool uv_find_nearest_vert(
struct Scene *scene, struct Image *ima, struct Object *obedit,
const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
+bool uv_find_nearest_vert_multi(
+ struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
+ const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
bool uv_find_nearest_edge(
struct Scene *scene, struct Image *ima, struct Object *obedit,
const float co[2], struct UvNearestHit *hit_final);
+bool uv_find_nearest_edge_multi(
+ struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
+ const float co[2], struct UvNearestHit *hit_final);
bool uv_find_nearest_face(
struct Scene *scene, struct Image *ima, struct Object *obedit,
const float co[2], struct UvNearestHit *hit_final);
+bool uv_find_nearest_face_multi(
+ struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
+ const float co[2], struct UvNearestHit *hit_final);
/* utility tool functions */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 9df0c7c89ed..c2e8c2b5786 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -66,6 +66,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -89,7 +90,10 @@
#include "uvedit_intern.h"
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action);
+static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
+static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len);
+static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
+static void uv_select_all_perform_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
@@ -794,6 +798,21 @@ bool uv_find_nearest_edge(
return found;
}
+bool uv_find_nearest_edge_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len,
+ const float co[2], UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
bool uv_find_nearest_face(
Scene *scene, Image *ima, Object *obedit, const float co[2],
UvNearestHit *hit_final)
@@ -837,6 +856,21 @@ bool uv_find_nearest_face(
return found;
}
+bool uv_find_nearest_face_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len,
+ const float co[2], UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
static bool uv_nearest_between(
const BMLoop *l, const float co[2],
const int cd_loop_uv_offset)
@@ -918,6 +952,21 @@ bool uv_find_nearest_vert(
return found;
}
+bool uv_find_nearest_vert_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len,
+ float const co[2], const float penalty_dist, UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -1043,9 +1092,10 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1,
}
static int uv_select_edgeloop(
- Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, UvNearestHit *hit,
+ Scene *scene, Image *ima, Object *obedit, UvNearestHit *hit,
const float limit[2], const bool extend)
{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter, liter;
BMLoop *l;
@@ -1064,7 +1114,7 @@ static int uv_select_edgeloop(
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
if (!extend) {
- uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
+ uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
}
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
@@ -1147,10 +1197,17 @@ static int uv_select_edgeloop(
/** \name Select Linked
* \{ */
-static void uv_select_linked(
- Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float limit[2],
+static void uv_select_linked_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, const float limit[2],
UvNearestHit *hit_final, bool extend, bool select_faces)
{
+ /* loop over objects, or just use hit_final->ob */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (hit_final && ob_index != 0) {
+ break;
+ }
+ Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
+
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1161,6 +1218,7 @@ static void uv_select_linked(
unsigned int a;
char *flag;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
@@ -1336,6 +1394,7 @@ static void uv_select_linked(
MEM_freeN(stack);
MEM_freeN(flag);
BM_uv_vert_map_free(vmap);
+ }
}
/* WATCH IT: this returns first selected UV,
@@ -1957,9 +2016,53 @@ static void UV_OT_weld(wmOperatorType *ot)
/** \name (De)Select All Operator
* \{ */
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action)
+
+static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
{
ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
+ }
+ else {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_select_is_any_selected(scene, ima, obedit)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
+{
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1967,8 +2070,11 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (action == SEL_TOGGLE) {
+ action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
+ }
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
switch (action) {
case SEL_TOGGLE:
EDBM_select_toggle_all(em);
@@ -1986,24 +2092,6 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd
}
}
else {
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- action = SEL_DESELECT;
- break;
- }
- }
- }
- }
-
-
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
@@ -2027,18 +2115,38 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd
}
}
+static void uv_select_all_perform_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
+{
+ if (action == SEL_TOGGLE) {
+ action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_all_perform(scene, ima, obedit, action);
+ }
+}
+
static int uv_select_all_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
int action = RNA_enum_get(op->ptr, "action");
- uv_select_all_perform(scene, ima, obedit, em, action);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects);
return OPERATOR_FINISHED;
}
@@ -2087,14 +2195,14 @@ static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], fl
return false;
}
-static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
+static int uv_mouse_select_multi(
+ bContext *C, Object **objects, uint objects_len,
+ const float co[2], bool extend, bool loop)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -2105,8 +2213,6 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
float limit[2], **hituv = NULL;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
/* notice 'limit' is the same no matter the zoom level, since this is like
* remove doubles and could annoying if it joined points when zoomed out.
* 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
@@ -2143,7 +2249,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* find nearest element */
if (loop) {
/* find edge */
- if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2151,7 +2257,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_VERTEX) {
/* find vertex */
- if (!uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, &hit)) {
+ if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2167,7 +2273,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_EDGE) {
/* find edge */
- if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2185,10 +2291,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_FACE) {
/* find face */
- if (!uv_find_nearest_face(scene, ima, obedit, co, &hit)) {
+ if (!uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
+ BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
/* make active */
BM_mesh_active_face_set(em->bm, hit.efa);
@@ -2205,7 +2314,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
hitlen = hit.efa->len;
}
else if (selectmode == UV_SELECT_ISLAND) {
- if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2216,12 +2325,24 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
return OPERATOR_CANCELLED;
}
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
/* do selection */
if (loop) {
- flush = uv_select_edgeloop(scene, ima, obedit, em, &hit, limit, extend);
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+ flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
}
else if (selectmode == UV_SELECT_ISLAND) {
- uv_select_linked(scene, ima, obedit, em, limit, &hit, extend, false);
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+ uv_select_linked_multi(scene, ima, objects, objects_len, limit, &hit, extend, false);
}
else if (extend) {
if (selectmode == UV_SELECT_VERTEX) {
@@ -2271,7 +2392,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else {
/* deselect all */
- uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
if (selectmode == UV_SELECT_VERTEX) {
/* select vertex */
@@ -2339,6 +2460,15 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
+static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
+{
+ 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_with_uvs(view_layer, &objects_len);
+ int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, loop);
+ MEM_freeN(objects);
+ return ret;
+}
static int uv_select_exec(bContext *C, wmOperator *op)
{
@@ -2443,9 +2573,8 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
float limit[2];
int extend;
bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
@@ -2460,6 +2589,9 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
extend = RNA_boolean_get(op->ptr, "extend");
uvedit_pixel_to_float(sima, limit, 0.05f);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
+
if (pick) {
float co[2];
@@ -2475,15 +2607,32 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
RNA_float_get_array(op->ptr, "location", co);
}
- if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ MEM_SAFE_FREE(objects);
return OPERATOR_CANCELLED;
}
}
- uv_select_linked(scene, ima, obedit, em, limit, pick ? &hit : NULL, extend, select_faces);
+ if (!extend) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ uv_select_linked_multi(scene, ima, objects, objects_len, limit, pick ? &hit : NULL, extend, select_faces);
+
+ /* weak!, but works */
+ Object **objects_free = objects;
+ if (pick) {
+ objects = &hit.ob;
+ objects_len = 1;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects_free);
return OPERATOR_FINISHED;
}
@@ -2879,23 +3028,20 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
rctf rectf;
- bool changed, pinned, select, extend;
+ bool pinned, select, extend;
const bool use_face_center = (
(ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
(ts->uv_selectmode == UV_SELECT_FACE));
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
/* get rectangle from operator */
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
@@ -2905,8 +3051,22 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
extend = RNA_boolean_get(op->ptr, "extend");
pinned = RNA_boolean_get(op->ptr, "pinned");
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
if (!extend)
- uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
/* do actual selection */
if (use_face_center && !pinned) {
@@ -2972,12 +3132,17 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
if (ts->uv_flag & UV_SYNC_SELECTION) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
-
- return OPERATOR_FINISHED;
+ }
+ changed_multi |= changed;
}
+ MEM_SAFE_FREE(objects);
+
+ if (changed_multi) {
+ return OPERATOR_FINISHED;
+ }
return OPERATOR_CANCELLED;
-}
+}
static void UV_OT_select_border(wmOperatorType *ot)
{
@@ -3131,36 +3296,46 @@ static void UV_OT_circle_select(wmOperatorType *ot)
/** \name Lasso Select Operator
* \{ */
-static bool do_lasso_select_mesh_uv(
- bContext *C, const int mcords[][2], short moves,
- const bool select, const bool extend)
+static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves,
+ const bool select, const bool extend)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool use_face_center = (
(ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
(ts->uv_selectmode == UV_SELECT_FACE));
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BMIter iter, liter;
BMFace *efa;
BMLoop *l;
int screen_uv[2];
- bool changed = false;
+ bool changed_multi = false;
rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ bool changed = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
if (!extend && select) {
- uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
if (use_face_center) { /* Face Center Sel */
@@ -3223,7 +3398,10 @@ static bool do_lasso_select_mesh_uv(
}
}
- return changed;
+ changed_multi |= changed;
+ }
+
+ return changed_multi;
}
static int uv_lasso_select_exec(bContext *C, wmOperator *op)
@@ -4175,7 +4353,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
me->drawflag |= ME_DRAWSEAMS;
if (scene->toolsettings->edge_mode_live_unwrap)
- ED_unwrap_lscm(scene, ob, false);
+ ED_unwrap_lscm(scene, ob, false, false);
DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 4f28d1f9eea..0e5f4886f3e 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -61,6 +61,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -202,6 +203,21 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit)
return false;
}
+static bool uvedit_have_selection_multi(
+ Scene *scene, Object **objects, const uint objects_len, bool implicit)
+{
+ bool have_select = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (uvedit_have_selection(scene, em, implicit)) {
+ have_select = true;
+ break;
+ }
+ }
+ return have_select;
+}
+
void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy)
{
bool sloppy = true;
@@ -258,9 +274,11 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no);
}
-static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
- const bool implicit, const bool fill, const bool sel,
- const bool correct_aspect)
+/* See: construct_param_handle_multi to handle multiple objects at once. */
+static ParamHandle *construct_param_handle(
+ Scene *scene, Object *ob, BMesh *bm,
+ const bool implicit, const bool fill, const bool sel,
+ const bool correct_aspect)
{
ParamHandle *handle;
BMFace *efa;
@@ -324,6 +342,89 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
return handle;
}
+/**
+ * Version of #construct_param_handle_single that handles multiple objects.
+ */
+static ParamHandle *construct_param_handle_multi(
+ Scene *scene, Object **objects, const uint objects_len,
+ const bool implicit, const bool fill, const bool sel,
+ const bool correct_aspect)
+{
+ ParamHandle *handle;
+ BMFace *efa;
+ BMLoop *l;
+ BMEdge *eed;
+ BMIter iter, liter;
+ int i;
+
+
+ handle = param_construct_begin();
+
+ if (correct_aspect) {
+ Object *ob = objects[0];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ float aspx, aspy;
+
+ ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
+ if (aspx != aspy) {
+ param_aspect_ratio(handle, aspx, aspy);
+ }
+ }
+
+ /* we need the vert indices */
+ EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT);
+
+ int offset = 0;
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+
+ if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
+ continue;
+ }
+
+ if (implicit) {
+ bool is_loopsel = false;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ is_loopsel = true;
+ break;
+ }
+ }
+ if (is_loopsel == false) {
+ continue;
+ }
+ }
+
+ construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
+ }
+
+ if (!implicit) {
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
+ ParamKey vkeys[2];
+ vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
+ vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
+ param_edge_set_seam(handle, vkeys);
+ }
+ }
+ }
+ offset += bm->totface;
+ }
+
+ param_construct_end(handle, fill, implicit);
+
+ return handle;
+}
+
static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select,
Scene *scene, const int cd_loop_uv_offset)
@@ -715,6 +816,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* ******************** Pack Islands operator **************** */
+
void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate)
{
ParamHandle *handle;
@@ -724,14 +826,29 @@ void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected,
param_delete(handle);
}
+void ED_uvedit_pack_islands_multi(
+ Scene *scene, Object **objects, const uint objects_len,
+ bool selected, bool correct_aspect, bool do_rotate)
+{
+ ParamHandle *handle;
+ handle = construct_param_handle_multi(
+ scene, objects, objects_len, true, false, selected, correct_aspect);
+ param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
+ param_flush(handle);
+ param_delete(handle);
+}
+
static int pack_islands_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool do_rotate = RNA_boolean_get(op->ptr, "rotate");
- if (!uvedit_have_selection(scene, em, true)) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, true)) {
+ MEM_SAFE_FREE(objects);
return OPERATOR_CANCELLED;
}
@@ -740,10 +857,15 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
else
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
- ED_uvedit_pack_islands(scene, obedit, em->bm, true, true, do_rotate);
-
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, do_rotate);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects);
return OPERATOR_FINISHED;
}
@@ -856,7 +978,7 @@ void ED_uvedit_live_unwrap(Scene *scene, Object *obedit)
if (scene->toolsettings->edge_mode_live_unwrap &&
CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV))
{
- ED_unwrap_lscm(scene, obedit, false); /* unwrap all not just sel */
+ ED_unwrap_lscm(scene, obedit, false, false); /* unwrap all not just sel */
}
}
@@ -1178,7 +1300,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
/* ******************** Unwrap operator **************** */
/* assumes UV Map is checked, doesn't run update funcs */
-void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
+void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel, const bool pack)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
ParamHandle *handle;
@@ -1199,7 +1321,10 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
param_lscm_end(handle);
param_average(handle);
- param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+
+ if (pack) {
+ param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+ }
param_flush(handle);
@@ -1208,33 +1333,48 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
static int unwrap_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
int method = RNA_enum_get(op->ptr, "method");
const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
- bool use_subsurf_final;
float obsize[3];
bool implicit = false;
- if (!uvedit_have_selection(scene, em, implicit)) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) {
+ MEM_SAFE_FREE(objects);
return OPERATOR_CANCELLED;
}
-
+
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bool use_subsurf_final;
+
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
- mat4_to_size(obsize, obedit->obmat);
- if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f))
- BKE_report(op->reports, RPT_INFO,
- "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh");
- else if (is_negative_m4(obedit->obmat))
- BKE_report(op->reports, RPT_INFO,
- "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
+ mat4_to_size(obsize, obedit->obmat);
+ if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f))
+ BKE_report(op->reports, RPT_INFO,
+ "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh");
+ else if (is_negative_m4(obedit->obmat))
+ BKE_report(op->reports, RPT_INFO,
+ "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
+
+
+ /* double up the check here but better keep ED_unwrap_lscm interface simple and not
+ * pass operator for warning append */
+ modifier_unwrap_state(obedit, scene, &use_subsurf_final);
+ if (use_subsurf != use_subsurf_final) {
+ BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap");
+ }
+ }
/* remember last method for live unwrap */
if (RNA_struct_property_is_set(op->ptr, "method"))
@@ -1257,17 +1397,17 @@ static int unwrap_exec(bContext *C, wmOperator *op)
if (use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
- /* double up the check here but better keep ED_unwrap_lscm interface simple and not
- * pass operator for warning append */
- modifier_unwrap_state(obedit, scene, &use_subsurf_final);
- if (use_subsurf != use_subsurf_final)
- BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap");
-
/* execute unwrap */
- ED_unwrap_lscm(scene, obedit, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_unwrap_lscm(scene, obedit, true, false);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, true);
+
+ MEM_SAFE_FREE(objects);
return OPERATOR_FINISHED;
}
@@ -1322,9 +1462,8 @@ static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
static int uv_from_view_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -1334,15 +1473,22 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
BMIter iter, liter;
MLoopUV *luv;
float rotmat[4][4];
+ bool changed_multi = false;
- int cd_loop_uv_offset;
+ 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];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool changed = false;
/* add uvs if they don't exist yet */
if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
+ continue;
}
- cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (RNA_boolean_get(op->ptr, "orthographic")) {
uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f);
@@ -1355,6 +1501,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
}
+ changed = true;
}
}
else if (camera) {
@@ -1372,6 +1519,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
}
+ changed = true;
}
MEM_freeN(uci);
@@ -1388,15 +1536,26 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
}
+ changed = true;
}
}
- uv_map_clip_correct(scene, obedit, em, op);
+ if (changed) {
+ uv_map_clip_correct(scene, obedit, em, op);
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ changed_multi = true;
+ }
+ }
+ MEM_SAFE_FREE(objects);
- return OPERATOR_FINISHED;
+ if (changed_multi) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static int uv_from_view_poll(bContext *C)