Blender V4.5
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 /* These type is not used for actual #CustomData layers. */
28 return std::nullopt;
29 case CD_MVERT:
30 case CD_MSTICKY:
31 case CD_MEDGE:
32 case CD_FACEMAP:
33 case CD_MTEXPOLY:
34 case CD_MLOOPUV:
35 case CD_MPOLY:
36 case CD_MLOOP:
37 case CD_BWEIGHT:
38 case CD_CREASE:
39 case CD_PAINT_MASK:
40 case CD_CUSTOMLOOPNORMAL:
41 case CD_SCULPT_FACE_SETS:
42 case CD_MTFACE:
44 /* These types are only used for versioning old files. */
45 return std::nullopt;
46 /* These types are only used for #BMesh. */
47 case CD_SHAPEKEY:
50 return std::nullopt;
51 case CD_MDEFORMVERT:
52 case CD_MFACE:
53 case CD_MCOL:
54 case CD_ORIGINDEX:
55 case CD_NORMAL:
56 case CD_ORIGSPACE:
57 case CD_ORCO:
58 case CD_TANGENT:
59 case CD_MDISPS:
60 case CD_CLOTH_ORCO:
63 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 AttributeStorage storage;
113 struct AttributeToAdd {
114 StringRef name;
115 AttrDomain domain;
116 AttrType type;
117 void *array_data;
118 int array_size;
119 const ImplicitSharingInfo *sharing_info;
120 };
122 Vector<AttributeToAdd> attributes_to_add;
123 for (const auto &item : domains.items()) {
124 const AttrDomain domain = item.key;
125 const CustomData &custom_data = item.value.data;
126 const int domain_size = item.value.size;
127 for (const CustomDataLayer &layer : MutableSpan(custom_data.layers, custom_data.totlayer)) {
128 if (const std::optional<AttrType> attr_type = custom_data_type_to_attr_type(
129 eCustomDataType(layer.type)))
130 {
131 /* Skip adding a user. This #CustomDataLayer is just freed below. */
132 attributes_to_add.append(
133 {layer.name, domain, *attr_type, layer.data, domain_size, layer.sharing_info});
134 }
135 else {
136 layers_to_keep.lookup_or_add_default(domain).append(layer);
137 }
138 }
139 }
140
141 for (AttributeToAdd &attribute : attributes_to_add) {
142 bke::Attribute::ArrayData array_data;
143 array_data.data = attribute.array_data;
144 array_data.size = attribute.array_size;
145 array_data.sharing_info = ImplicitSharingPtr<>(attribute.sharing_info);
146 storage.add(storage.unique_name_calc(attribute.name),
147 attribute.domain,
148 attribute.type,
149 std::move(array_data));
150 }
151
152 for (const auto &[domain, custom_data] : domains.items()) {
153 Vector layers_vector = layers_to_keep.pop_default(domain, {});
154 MEM_SAFE_FREE(custom_data.data.layers);
155 custom_data.data.totlayer = 0;
156 custom_data.data.maxlayer = 0;
157 if (layers_vector.is_empty()) {
158 CustomData_update_typemap(&custom_data.data);
159 continue;
160 }
161 VectorData data = layers_vector.release();
162 custom_data.data.layers = data.data;
163 custom_data.data.totlayer = data.size;
164 custom_data.data.maxlayer = data.capacity;
165 CustomData_update_typemap(&custom_data.data);
166 }
167
168 return storage;
169}
170
171std::optional<eCustomDataType> attr_type_to_custom_data_type(const AttrType attr_type)
172{
173 switch (attr_type) {
174 case AttrType::Bool:
175 return CD_PROP_BOOL;
176 case AttrType::Int8:
177 return CD_PROP_INT8;
179 return CD_PROP_INT16_2D;
180 case AttrType::Int32:
181 return CD_PROP_INT32;
183 return CD_PROP_INT32_2D;
184 case AttrType::Float:
185 return CD_PROP_FLOAT;
186 case AttrType::Float2:
187 return CD_PROP_FLOAT2;
188 case AttrType::Float3:
189 return CD_PROP_FLOAT3;
191 return CD_PROP_FLOAT4X4;
193 return CD_PROP_BYTE_COLOR;
195 return CD_PROP_COLOR;
197 return CD_PROP_QUATERNION;
198 case AttrType::String:
199 return CD_PROP_STRING;
200 }
201 return std::nullopt;
202}
203
208
210 AttributeStorage &storage,
211 const Map<AttrDomain, CustomDataAndSizeMutable> &custom_data_domains)
212{
213 /* Name uniqueness is handled by the #CustomData API. */
214 storage.foreach([&](const Attribute &attribute) {
215 const std::optional<eCustomDataType> data_type = attr_type_to_custom_data_type(
216 attribute.data_type());
217 if (!data_type) {
218 return;
219 }
220 CustomData &custom_data = custom_data_domains.lookup(attribute.domain()).data;
221 const int domain_size = custom_data_domains.lookup(attribute.domain()).size;
222 if (const auto *array_data = std::get_if<Attribute::ArrayData>(&attribute.data())) {
223 BLI_assert(array_data->size == domain_size);
225 *data_type,
226 array_data->data,
227 array_data->size,
228 attribute.name(),
229 array_data->sharing_info.get());
230 }
231 else if (const auto *single_data = std::get_if<Attribute::SingleData>(&attribute.data())) {
232 const CPPType &cpp_type = *custom_data_type_to_cpp_type(*data_type);
233 auto *value = new ImplicitSharedValue<GArray<>>(cpp_type, domain_size);
234 cpp_type.fill_construct_n(single_data->value, value->data.data(), domain_size);
236 &custom_data, *data_type, value->data.data(), domain_size, attribute.name(), value);
237 }
238 });
239 storage = {};
240}
241
243{
244 convert_storage_to_customdata(mesh.attribute_storage.wrap(),
245 {{AttrDomain::Point, {mesh.vert_data, mesh.verts_num}},
246 {AttrDomain::Edge, {mesh.edge_data, mesh.edges_num}},
247 {AttrDomain::Face, {mesh.face_data, mesh.faces_num}},
248 {AttrDomain::Corner, {mesh.corner_data, mesh.corners_num}}});
249 if (const char *name = mesh.active_uv_map_attribute) {
250 const int layer_n = CustomData_get_named_layer(&mesh.corner_data, CD_PROP_FLOAT2, name);
251 if (layer_n != -1) {
252 CustomData_set_layer_active(&mesh.corner_data, CD_PROP_FLOAT2, layer_n);
253 }
254 MEM_freeN(mesh.active_uv_map_attribute);
255 mesh.active_uv_map_attribute = nullptr;
256 }
257 if (const char *name = mesh.default_uv_map_attribute) {
258 const int layer_n = CustomData_get_named_layer(&mesh.corner_data, CD_PROP_FLOAT2, name);
259 if (layer_n != -1) {
260 CustomData_set_layer_render(&mesh.corner_data, CD_PROP_FLOAT2, layer_n);
261 }
262 MEM_freeN(mesh.default_uv_map_attribute);
263 mesh.default_uv_map_attribute = nullptr;
264 }
265}
267{
269 {{AttrDomain::Point, {mesh.vert_data, mesh.verts_num}},
270 {AttrDomain::Edge, {mesh.edge_data, mesh.edges_num}},
271 {AttrDomain::Face, {mesh.face_data, mesh.faces_num}},
272 {AttrDomain::Corner, {mesh.corner_data, mesh.corners_num}}});
273}
274
276{
277 convert_storage_to_customdata(curves.attribute_storage.wrap(),
278 {{AttrDomain::Point, {curves.point_data, curves.points_num()}},
279 {AttrDomain::Curve, {curves.curve_data, curves.curves_num()}}});
280}
282{
284 {{AttrDomain::Point, {curves.point_data, curves.points_num()}},
285 {AttrDomain::Curve, {curves.curve_data, curves.curves_num()}}});
286}
287
289{
291 {{AttrDomain::Point, {pointcloud.pdata, pointcloud.totpoint}}});
292}
293
299
301{
303 grease_pencil.attribute_storage.wrap(),
304 {{AttrDomain::Layer, {grease_pencil.layers_data, int(grease_pencil.layers().size())}}});
305}
307{
309 {{AttrDomain::Layer, {grease_pencil.layers_data, int(grease_pencil.layers().size())}}});
310}
311
312} // 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_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_FREESTYLE_EDGE
@ CD_FREESTYLE_FACE
@ CD_GRID_PAINT_MASK
@ CD_PROP_INT16_2D
@ CD_CLOTH_ORCO
@ CD_PROP_STRING
@ CD_PROP_FLOAT4X4
@ CD_AUTO_FROM_NAME
@ CD_SHAPE_KEYINDEX
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 DataVariant & data() const
#define MEM_SAFE_FREE(v)
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)
std::optional< AttrType > custom_data_type_to_attr_type(eCustomDataType data_type)
void mesh_convert_customdata_to_storage(Mesh &mesh)
void pointcloud_convert_storage_to_customdata(PointCloud &pointcloud)
static AttributeStorage attribute_legacy_convert_customdata_to_storage(const Map< AttrDomain, CustomDataAndSize > &domains)
void mesh_convert_storage_to_customdata(Mesh &mesh)
void grease_pencil_convert_storage_to_customdata(GreasePencil &grease_pencil)
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)
void curves_convert_storage_to_customdata(CurvesGeometry &curves)
CustomDataLayer * layers
struct AttributeStorage attribute_storage
struct AttributeStorage attribute_storage
struct CustomData pdata