Mesh: Add versioning to convert old face maps to boolean attributes

See #105317

In 46cf093270, face maps were just converted to an integer
attribute. While the internal data remains the same that way, we lose
the names and some convenient methods of interaction. This commit
additionally converts each face map to a separate boolean attribute
using the old name. This does require that no attributes were using that
name already.

Each boolean attribute can be thought of as a selection, accessible in
geometry nodes and properly interpolated by mesh processing
algorithms. The selections no longer have to be unique, meaning
one face can be part of multiple selections.

Pull Request: https://projects.blender.org/blender/blender/pulls/113769
This commit is contained in:
Hans Goudey
2023-10-17 09:17:07 +02:00
committed by Hans Goudey
parent bbf87ee78c
commit 820f0c24c4
6 changed files with 68 additions and 11 deletions
@@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 33
#define BLENDER_FILE_SUBVERSION 34
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
@@ -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.
@@ -16,11 +16,14 @@
#include "DNA_meshdata_types.h"
#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"
@@ -30,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"
@@ -1345,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;
@@ -1364,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);
@@ -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 */
@@ -346,6 +356,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. */