Merge branch 'blender-v4.0-release'
This commit is contained in:
commit
4ae4e25dc2
|
@ -1902,6 +1902,10 @@ class VIEW3D_MT_select_edit_mesh(Menu):
|
|||
layout.operator("mesh.select_axis", text="Side of Active")
|
||||
layout.operator("mesh.select_mirror")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("mesh.select_by_attribute", text="By Attribute")
|
||||
|
||||
layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label)
|
||||
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh);
|
|||
|
||||
void BKE_mesh_legacy_convert_loops_to_corners(Mesh *mesh);
|
||||
|
||||
void BKE_mesh_legacy_face_map_to_generic(Mesh *mesh);
|
||||
void BKE_mesh_legacy_face_map_to_generic(Main *bmain);
|
||||
|
||||
/**
|
||||
* Recreate #MFace Tessellation.
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_multi_value_map.hh"
|
||||
#include "BLI_polyfill_2d.h"
|
||||
#include "BLI_resource_scope.hh"
|
||||
#include "BLI_string.h"
|
||||
|
@ -31,6 +33,7 @@
|
|||
#include "BKE_attribute.hh"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_legacy_convert.hh"
|
||||
#include "BKE_multires.hh"
|
||||
|
@ -1346,18 +1349,18 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh)
|
|||
/** \name Face Map Conversion
|
||||
* \{ */
|
||||
|
||||
void BKE_mesh_legacy_face_map_to_generic(Mesh *mesh)
|
||||
static void move_face_map_data_to_attributes(Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
if (mesh->attributes().contains("face_maps")) {
|
||||
return;
|
||||
}
|
||||
void *data = nullptr;
|
||||
int *data = nullptr;
|
||||
const ImplicitSharingInfo *sharing_info = nullptr;
|
||||
for (const int i : IndexRange(mesh->face_data.totlayer)) {
|
||||
CustomDataLayer &layer = mesh->face_data.layers[i];
|
||||
if (layer.type == CD_FACEMAP) {
|
||||
data = layer.data;
|
||||
data = static_cast<int *>(layer.data);
|
||||
sharing_info = layer.sharing_info;
|
||||
layer.data = nullptr;
|
||||
layer.sharing_info = nullptr;
|
||||
|
@ -1365,13 +1368,53 @@ void BKE_mesh_legacy_face_map_to_generic(Mesh *mesh)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (data != nullptr) {
|
||||
CustomData_add_layer_named_with_data(
|
||||
&mesh->face_data, CD_PROP_INT32, data, mesh->faces_num, "face_maps", sharing_info);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
CustomData_add_layer_named_with_data(
|
||||
&mesh->face_data, CD_PROP_INT32, data, mesh->faces_num, "face_maps", sharing_info);
|
||||
if (sharing_info != nullptr) {
|
||||
sharing_info->remove_user_and_delete_if_last();
|
||||
}
|
||||
|
||||
MultiValueMap<int, int> groups;
|
||||
for (const int i : IndexRange(mesh->faces_num)) {
|
||||
if (data[i] == -1) {
|
||||
/* -1 values "didn't have" a face map. */
|
||||
continue;
|
||||
}
|
||||
groups.add(data[i], i);
|
||||
}
|
||||
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
for (const auto item : groups.items()) {
|
||||
bke::SpanAttributeWriter<bool> attribute = attributes.lookup_or_add_for_write_span<bool>(
|
||||
".temp_face_map_" + std::to_string(item.key), ATTR_DOMAIN_FACE);
|
||||
if (attribute) {
|
||||
attribute.span.fill_indices(item.value.as_span(), true);
|
||||
attribute.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_mesh_legacy_face_map_to_generic(Main *bmain)
|
||||
{
|
||||
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
|
||||
move_face_map_data_to_attributes(mesh);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Object *, object, &bmain->objects) {
|
||||
if (object->type != OB_MESH) {
|
||||
continue;
|
||||
}
|
||||
Mesh *mesh = static_cast<Mesh *>(object->data);
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (bFaceMap *, face_map, &object->fmaps, i) {
|
||||
mesh->attributes_for_write().rename(".temp_face_map_" + std::to_string(i), face_map->name);
|
||||
}
|
||||
BLI_freelistN(&object->fmaps);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -707,6 +707,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
|
||||
/* Only for versioning, vertex group names are now stored on object data. */
|
||||
BLO_read_list(reader, &ob->defbase);
|
||||
BLO_read_list(reader, &ob->fmaps);
|
||||
|
||||
/* XXX deprecated - old animation system <<< */
|
||||
direct_link_nlastrips(reader, &ob->nlastrips);
|
||||
|
|
|
@ -311,6 +311,10 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 34)) {
|
||||
BKE_mesh_legacy_face_map_to_generic(bmain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
@ -1097,9 +1101,6 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 6)) {
|
||||
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
|
||||
BKE_mesh_legacy_face_map_to_generic(mesh);
|
||||
}
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
versioning_replace_legacy_glossy_node(ntree);
|
||||
versioning_remove_microfacet_sharp_distribution(ntree);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* \ingroup edmesh
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
|
@ -5358,4 +5360,108 @@ void MESH_OT_loop_to_region(wmOperatorType *ot)
|
|||
"Select bigger regions instead of smaller ones");
|
||||
}
|
||||
|
||||
static bool edbm_select_by_attribute_poll(bContext *C)
|
||||
{
|
||||
if (!ED_operator_editmesh(C)) {
|
||||
return false;
|
||||
}
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
const Mesh *mesh = static_cast<const Mesh *>(obedit->data);
|
||||
const CustomDataLayer *layer = BKE_id_attributes_active_get(&const_cast<ID &>(mesh->id));
|
||||
if (!layer) {
|
||||
CTX_wm_operator_poll_msg_set(C, "There must be an active attribute");
|
||||
return false;
|
||||
}
|
||||
if (layer->type != CD_PROP_BOOL) {
|
||||
CTX_wm_operator_poll_msg_set(C, "The active attribute must have a boolean type");
|
||||
return false;
|
||||
}
|
||||
if (BKE_id_attribute_domain(&mesh->id, layer) == ATTR_DOMAIN_CORNER) {
|
||||
CTX_wm_operator_poll_msg_set(
|
||||
C, "The active attribute must be on the vertex, edge, or face domain");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::optional<BMIterType> domain_to_iter_type(const eAttrDomain domain)
|
||||
{
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return BM_VERTS_OF_MESH;
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return BM_EDGES_OF_MESH;
|
||||
case ATTR_DOMAIN_FACE:
|
||||
return BM_FACES_OF_MESH;
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
static int edbm_select_by_attribute_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(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(
|
||||
scene, view_layer, CTX_wm_view3d(C), &objects_len);
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
Mesh *mesh = static_cast<Mesh *>(obedit->data);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMesh *bm = em->bm;
|
||||
|
||||
const CustomDataLayer *layer = BKE_id_attributes_active_get(&mesh->id);
|
||||
if (!layer) {
|
||||
continue;
|
||||
}
|
||||
if (layer->type != CD_PROP_BOOL) {
|
||||
continue;
|
||||
}
|
||||
if (BKE_id_attribute_domain(&mesh->id, layer) == ATTR_DOMAIN_CORNER) {
|
||||
continue;
|
||||
}
|
||||
const std::optional<BMIterType> iter_type = domain_to_iter_type(
|
||||
BKE_id_attribute_domain(&mesh->id, layer));
|
||||
if (!iter_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
BMElem *elem;
|
||||
BMIter iter;
|
||||
BM_ITER_MESH (elem, &iter, bm, *iter_type) {
|
||||
if (BM_elem_flag_test(elem, BM_ELEM_HIDDEN | BM_ELEM_SELECT)) {
|
||||
continue;
|
||||
}
|
||||
if (BM_ELEM_CD_GET_BOOL(elem, layer->offset)) {
|
||||
BM_elem_select_set(bm, elem, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
EDBM_selectmode_flush(em);
|
||||
|
||||
DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
||||
}
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void MESH_OT_select_by_attribute(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Select by Attribute";
|
||||
ot->idname = "MESH_OT_select_by_attribute";
|
||||
ot->description = "Select elements based on the active boolean attribute";
|
||||
|
||||
ot->exec = edbm_select_by_attribute_exec;
|
||||
ot->poll = edbm_select_by_attribute_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -228,6 +228,7 @@ void MESH_OT_select_ungrouped(struct wmOperatorType *ot);
|
|||
void MESH_OT_select_axis(struct wmOperatorType *ot);
|
||||
void MESH_OT_region_to_loop(struct wmOperatorType *ot);
|
||||
void MESH_OT_loop_to_region(struct wmOperatorType *ot);
|
||||
void MESH_OT_select_by_attribute(struct wmOperatorType *ot);
|
||||
void MESH_OT_shortest_path_select(struct wmOperatorType *ot);
|
||||
|
||||
extern struct EnumPropertyItem *corner_type_items;
|
||||
|
|
|
@ -73,6 +73,7 @@ void ED_operatortypes_mesh()
|
|||
WM_operatortype_append(MESH_OT_edge_rotate);
|
||||
WM_operatortype_append(MESH_OT_shortest_path_select);
|
||||
WM_operatortype_append(MESH_OT_loop_to_region);
|
||||
WM_operatortype_append(MESH_OT_select_by_attribute);
|
||||
WM_operatortype_append(MESH_OT_region_to_loop);
|
||||
WM_operatortype_append(MESH_OT_select_axis);
|
||||
|
||||
|
|
|
@ -60,6 +60,16 @@ typedef struct bDeformGroup {
|
|||
char flag, _pad0[7];
|
||||
} bDeformGroup;
|
||||
|
||||
#ifdef DNA_DEPRECATED_ALLOW
|
||||
typedef struct bFaceMap {
|
||||
struct bFaceMap *next, *prev;
|
||||
/** MAX_VGROUP_NAME. */
|
||||
char name[64];
|
||||
char flag;
|
||||
char _pad0[7];
|
||||
} bFaceMap;
|
||||
#endif
|
||||
|
||||
#define MAX_VGROUP_NAME 64
|
||||
|
||||
/** #bDeformGroup::flag */
|
||||
|
@ -349,6 +359,7 @@ typedef struct Object {
|
|||
ListBase constraintChannels DNA_DEPRECATED; /* XXX deprecated... old animation system */
|
||||
ListBase effect DNA_DEPRECATED; /* XXX deprecated... keep for readfile */
|
||||
ListBase defbase DNA_DEPRECATED; /* Only for versioning, moved to object data. */
|
||||
ListBase fmaps DNA_DEPRECATED; /* For versioning, moved to generic attributes. */
|
||||
/** List of ModifierData structures. */
|
||||
ListBase modifiers;
|
||||
/** List of GpencilModifierData structures. */
|
||||
|
|
Loading…
Reference in New Issue