Blender V5.0
attribute_legacy_convert.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#define DNA_DEPRECATED_ALLOW
6
7#include <optional>
8
10#include "DNA_mesh_types.h"
12
13#include "BKE_attribute.hh"
14#include "BKE_curves.hh"
15#include "BKE_customdata.hh"
16
18
19namespace blender::bke {
20
21std::optional<AttrType> custom_data_type_to_attr_type(const eCustomDataType data_type)
22{
23 switch (data_type) {
24 case CD_NUMTYPES:
26 case CD_TANGENT:
27 /* These type is not used for actual #CustomData layers. */
29 return std::nullopt;
30 case CD_MVERT:
31 case CD_MSTICKY:
32 case CD_MEDGE:
33 case CD_FACEMAP:
34 case CD_MTEXPOLY:
35 case CD_MLOOPUV:
36 case CD_MPOLY:
37 case CD_MLOOP:
38 case CD_BWEIGHT:
39 case CD_CREASE:
40 case CD_PAINT_MASK:
41 case CD_CUSTOMLOOPNORMAL:
42 case CD_SCULPT_FACE_SETS:
43 case CD_MTFACE:
45 case CD_FREESTYLE_EDGE:
46 case CD_FREESTYLE_FACE:
47 /* These types are only used for versioning old files. */
48 return std::nullopt;
49 case CD_SHAPEKEY:
52 /* These types are only used for #BMesh. */
53 return std::nullopt;
54 case CD_MDEFORMVERT:
55 case CD_MFACE:
56 case CD_MCOL:
57 case CD_ORIGINDEX:
58 case CD_NORMAL:
59 case CD_ORIGSPACE:
60 case CD_ORCO:
61 case CD_MDISPS:
62 case CD_CLOTH_ORCO:
65 case CD_MVERT_SKIN:
66 case CD_MLOOPTANGENT:
67 /* These types are not generic. They will either be moved to some generic data type or
68 * #AttributeStorage will be extended to be able to support a similar format. */
69 return std::nullopt;
70 case CD_PROP_FLOAT:
71 return AttrType::Float;
72 case CD_PROP_INT32:
73 return AttrType::Int32;
77 return AttrType::Float4x4;
79 return AttrType::Int16_2D;
80 case CD_PROP_INT8:
81 return AttrType::Int8;
83 return AttrType::Int32_2D;
84 case CD_PROP_COLOR:
86 case CD_PROP_FLOAT3:
87 return AttrType::Float3;
88 case CD_PROP_FLOAT2:
89 return AttrType::Float2;
90 case CD_PROP_BOOL:
91 return AttrType::Bool;
92 case CD_PROP_STRING:
93 return AttrType::String;
96 }
97 return std::nullopt;
98}
99
104
111{
112 struct AttributeToAdd {
114 AttrDomain domain;
115 AttrType type;
116 void *array_data;
117 int array_size;
118 const ImplicitSharingInfo *sharing_info;
119 };
121 Vector<AttributeToAdd> attributes_to_add;
122 for (const auto &item : domains.items()) {
123 const AttrDomain domain = item.key;
124 const CustomData &custom_data = item.value.data;
125 const int domain_size = item.value.size;
126 for (const CustomDataLayer &layer : MutableSpan(custom_data.layers, custom_data.totlayer)) {
127 if (const std::optional<AttrType> attr_type = custom_data_type_to_attr_type(
128 eCustomDataType(layer.type)))
129 {
130 /* Skip adding a user. This #CustomDataLayer is just freed below. */
131 attributes_to_add.append(
132 {layer.name, domain, *attr_type, layer.data, domain_size, layer.sharing_info});
133 }
134 else {
135 layers_to_keep.lookup_or_add_default(domain).append(layer);
136 }
137 }
138 }
139
140 for (AttributeToAdd &attribute : attributes_to_add) {
141 bke::Attribute::ArrayData array_data;
142 array_data.data = attribute.array_data;
143 array_data.size = attribute.array_size;
144 array_data.sharing_info = ImplicitSharingPtr<>(attribute.sharing_info);
145 storage.add(storage.unique_name_calc(attribute.name),
146 attribute.domain,
147 attribute.type,
148 std::move(array_data));
149 }
150
151 for (const auto &[domain, custom_data] : domains.items()) {
152 Vector layers_vector = layers_to_keep.pop_default(domain, {});
153 MEM_SAFE_FREE(custom_data.data.layers);
154 custom_data.data.totlayer = 0;
155 custom_data.data.maxlayer = 0;
156 if (layers_vector.is_empty()) {
157 CustomData_update_typemap(&custom_data.data);
158 continue;
159 }
160 VectorData data = layers_vector.release();
161 custom_data.data.layers = data.data;
162 custom_data.data.totlayer = data.size;
163 custom_data.data.maxlayer = data.capacity;
164 CustomData_update_typemap(&custom_data.data);
165 }
166}
167
168std::optional<eCustomDataType> attr_type_to_custom_data_type(const AttrType attr_type)
169{
170 switch (attr_type) {
171 case AttrType::Bool:
172 return CD_PROP_BOOL;
173 case AttrType::Int8:
174 return CD_PROP_INT8;
176 return CD_PROP_INT16_2D;
177 case AttrType::Int32:
178 return CD_PROP_INT32;
180 return CD_PROP_INT32_2D;
181 case AttrType::Float:
182 return CD_PROP_FLOAT;
183 case AttrType::Float2:
184 return CD_PROP_FLOAT2;
185 case AttrType::Float3:
186 return CD_PROP_FLOAT3;
188 return CD_PROP_FLOAT4X4;
190 return CD_PROP_BYTE_COLOR;
192 return CD_PROP_COLOR;
194 return CD_PROP_QUATERNION;
195 case AttrType::String:
196 return CD_PROP_STRING;
197 }
198 return std::nullopt;
199}
200
205
207 AttributeStorage &storage,
208 const Map<AttrDomain, CustomDataAndSizeMutable> &custom_data_domains)
209{
210 /* Name uniqueness is handled by the #CustomData API. */
211 storage.foreach([&](const Attribute &attribute) {
212 const std::optional<eCustomDataType> data_type = attr_type_to_custom_data_type(
213 attribute.data_type());
214 if (!data_type) {
215 return;
216 }
217 CustomData &custom_data = custom_data_domains.lookup(attribute.domain()).data;
218 const int domain_size = custom_data_domains.lookup(attribute.domain()).size;
219 if (const auto *array_data = std::get_if<Attribute::ArrayData>(&attribute.data())) {
220 BLI_assert(array_data->size == domain_size);
222 *data_type,
223 array_data->data,
224 array_data->size,
225 attribute.name(),
226 array_data->sharing_info.get());
227 }
228 else if (const auto *single_data = std::get_if<Attribute::SingleData>(&attribute.data())) {
229 const CPPType &cpp_type = *custom_data_type_to_cpp_type(*data_type);
230 auto *value = new ImplicitSharedValue<GArray<>>(cpp_type, domain_size);
231 cpp_type.fill_construct_n(single_data->value, value->data.data(), domain_size);
233 &custom_data, *data_type, value->data.data(), domain_size, attribute.name(), value);
234 }
235 });
236 storage = {};
237}
238
240{
241 convert_storage_to_customdata(mesh.attribute_storage.wrap(),
242 {{AttrDomain::Point, {mesh.vert_data, mesh.verts_num}},
243 {AttrDomain::Edge, {mesh.edge_data, mesh.edges_num}},
244 {AttrDomain::Face, {mesh.face_data, mesh.faces_num}},
245 {AttrDomain::Corner, {mesh.corner_data, mesh.corners_num}}});
246 if (const char *name = mesh.active_uv_map_attribute) {
247 const int layer_n = CustomData_get_named_layer(&mesh.corner_data, CD_PROP_FLOAT2, name);
248 if (layer_n != -1) {
249 CustomData_set_layer_active(&mesh.corner_data, CD_PROP_FLOAT2, layer_n);
250 }
251 MEM_freeN(mesh.active_uv_map_attribute);
252 mesh.active_uv_map_attribute = nullptr;
253 }
254 if (const char *name = mesh.default_uv_map_attribute) {
255 const int layer_n = CustomData_get_named_layer(&mesh.corner_data, CD_PROP_FLOAT2, name);
256 if (layer_n != -1) {
257 CustomData_set_layer_render(&mesh.corner_data, CD_PROP_FLOAT2, layer_n);
258 }
259 MEM_freeN(mesh.default_uv_map_attribute);
260 mesh.default_uv_map_attribute = nullptr;
261 }
262}
264{
266 {{AttrDomain::Point, {mesh.vert_data, mesh.verts_num}},
267 {AttrDomain::Edge, {mesh.edge_data, mesh.edges_num}},
268 {AttrDomain::Face, {mesh.face_data, mesh.faces_num}},
269 {AttrDomain::Corner, {mesh.corner_data, mesh.corners_num}}},
270 mesh.attribute_storage.wrap());
271}
272
274{
276 {{AttrDomain::Point, {curves.point_data, curves.points_num()}},
277 {AttrDomain::Curve, {curves.curve_data_legacy, curves.curves_num()}}},
278 curves.attribute_storage.wrap());
279 CustomData_reset(&curves.curve_data_legacy);
280 /* Update the curve type count again (the first time was done on file-read, where
281 * #AttributeStorage data doesn't exist yet for older files). */
282 curves.update_curve_types();
283}
284
292
294{
297 {grease_pencil.layers_data_legacy, int(grease_pencil.layers().size())}}},
298 grease_pencil.attribute_storage.wrap());
299 CustomData_reset(&grease_pencil.layers_data_legacy);
300}
301
302} // namespace blender::bke
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_named_layer(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_set_layer_render(CustomData *data, eCustomDataType type, int n)
void CustomData_reset(CustomData *data)
void CustomData_update_typemap(CustomData *data)
const void * CustomData_add_layer_named_with_data(CustomData *data, eCustomDataType type, void *layer_data, int totelem, blender::StringRef name, const blender::ImplicitSharingInfo *sharing_info)
void CustomData_set_layer_active(CustomData *data, eCustomDataType type, int n)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
@ CD_PROP_BYTE_COLOR
@ CD_MLOOPTANGENT
@ CD_MVERT_SKIN
@ CD_PROP_FLOAT
@ CD_TESSLOOPNORMAL
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_MDEFORMVERT
@ CD_PROP_COLOR
@ CD_PROP_QUATERNION
@ CD_BM_ELEM_PYPTR
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_ORIGSPACE_MLOOP
@ CD_GRID_PAINT_MASK
@ CD_PROP_INT16_2D
@ CD_CLOTH_ORCO
@ CD_PROP_STRING
@ CD_PROP_FLOAT4X4
@ CD_AUTO_FROM_NAME
@ CD_SHAPE_KEYINDEX
#define MEM_SAFE_FREE(v)
BMesh const char void * data
void fill_construct_n(const void *value, void *dst, int64_t n) const
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value pop_default(const Key &key, const Value &default_value)
Definition BLI_map.hh:439
ItemIterator items() const &
Definition BLI_map.hh:902
void append(const T &value)
bool is_empty() const
VectorData< T, Allocator > release()
Attribute & add(std::string name, bke::AttrDomain domain, bke::AttrType data_type, Attribute::DataVariant data)
void foreach(FunctionRef< void(Attribute &)> fn)
std::string unique_name_calc(StringRef name) const
const DataVariant & data() const
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
std::optional< eCustomDataType > attr_type_to_custom_data_type(AttrType attr_type)
void pointcloud_convert_customdata_to_storage(PointCloud &pointcloud)
static void attribute_legacy_convert_customdata_to_storage(const Map< AttrDomain, CustomDataAndSize > &domains, AttributeStorage &storage)
std::optional< AttrType > custom_data_type_to_attr_type(eCustomDataType data_type)
void mesh_convert_customdata_to_storage(Mesh &mesh)
void mesh_convert_storage_to_customdata(Mesh &mesh)
void curves_convert_customdata_to_storage(CurvesGeometry &curves)
void grease_pencil_convert_customdata_to_storage(GreasePencil &grease_pencil)
static void convert_storage_to_customdata(AttributeStorage &storage, const Map< AttrDomain, CustomDataAndSizeMutable > &custom_data_domains)
const CPPType * custom_data_type_to_cpp_type(eCustomDataType type)
const char * name
CustomDataLayer * layers
struct AttributeStorage attribute_storage
struct AttributeStorage attribute_storage
struct CustomData pdata_legacy