Blender V4.5
bake_items_serialize.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6#include "BKE_bake_items.hh"
8#include "BKE_curves.hh"
9#include "BKE_customdata.hh"
10#include "BKE_grease_pencil.hh"
11#include "BKE_instances.hh"
12#include "BKE_lib_id.hh"
13#include "BKE_mesh.hh"
14#include "BKE_pointcloud.hh"
15#include "BKE_volume.hh"
16
17#include "BLI_endian_defines.h"
18#include "BLI_endian_switch.h"
19#include "BLI_listbase.h"
21#include "BLI_path_utils.hh"
22#include "BLI_string.h"
23
24#include "DNA_object_types.h"
25#include "DNA_volume_types.h"
26
27#include "RNA_access.hh"
28#include "RNA_enum_types.hh"
29
30#include <fmt/format.h>
31#include <sstream>
32#include <xxhash.h>
33
34#ifdef WITH_OPENVDB
35# include <openvdb/io/Stream.h>
36# include <openvdb/openvdb.h>
37
38# include "BKE_volume_grid.hh"
39#endif
40
41namespace blender::bke::bake {
42
43using namespace io::serialize;
44using DictionaryValuePtr = std::shared_ptr<DictionaryValue>;
45
46std::shared_ptr<DictionaryValue> BlobSlice::serialize() const
47{
48 auto io_slice = std::make_shared<DictionaryValue>();
49 io_slice->append_str("name", this->name);
50 io_slice->append_int("start", range.start());
51 io_slice->append_int("size", range.size());
52 return io_slice;
53}
54
55std::optional<BlobSlice> BlobSlice::deserialize(const DictionaryValue &io_slice)
56{
57 const std::optional<StringRefNull> name = io_slice.lookup_str("name");
58 const std::optional<int64_t> start = io_slice.lookup_int("start");
59 const std::optional<int64_t> size = io_slice.lookup_int("size");
60 if (!name || !start || !size) {
61 return std::nullopt;
62 }
63
64 return BlobSlice{*name, {*start, *size}};
65}
66
68 const FunctionRef<void(std::ostream &)> fn)
69{
70 std::ostringstream stream{std::ios::binary};
71 fn(stream);
72 std::string data = stream.rdbuf()->str();
73 return this->write(data.data(), data.size());
74}
75
76bool BlobReader::read_as_stream(const BlobSlice &slice, FunctionRef<bool(std::istream &)> fn) const
77{
78 const int64_t size = slice.range.size();
79 std::string buffer;
80 buffer.resize(size);
81 if (!this->read(slice, buffer.data())) {
82 return false;
83 }
84 std::istringstream stream{buffer, std::ios::binary};
85 if (!fn(stream)) {
86 return false;
87 }
88 return true;
89}
90
91DiskBlobReader::DiskBlobReader(std::string blobs_dir) : blobs_dir_(std::move(blobs_dir)) {}
92
93[[nodiscard]] bool DiskBlobReader::read(const BlobSlice &slice, void *r_data) const
94{
95 if (slice.range.is_empty()) {
96 return true;
97 }
98
99 char blob_path[FILE_MAX];
100 BLI_path_join(blob_path, sizeof(blob_path), blobs_dir_.c_str(), slice.name.c_str());
101
102 std::lock_guard lock{mutex_};
103 std::unique_ptr<fstream> &blob_file = open_input_streams_.lookup_or_add_cb_as(blob_path, [&]() {
104 return std::make_unique<fstream>(blob_path, std::ios::in | std::ios::binary);
105 });
106 blob_file->seekg(slice.range.start());
107 blob_file->read(static_cast<char *>(r_data), slice.range.size());
108 if (blob_file->gcount() != slice.range.size()) {
109 return false;
110 }
111 return true;
112}
113
114DiskBlobWriter::DiskBlobWriter(std::string blob_dir, std::string base_name)
115 : blob_dir_(std::move(blob_dir)), base_name_(std::move(base_name))
116{
117 blob_name_ = base_name_ + ".blob";
118}
119
121{
122 if (!blob_stream_.is_open()) {
123 char blob_path[FILE_MAX];
124 BLI_path_join(blob_path, sizeof(blob_path), blob_dir_.c_str(), blob_name_.c_str());
126 blob_stream_.open(blob_path, std::ios::out | std::ios::binary);
127 }
128
129 const int64_t old_offset = current_offset_;
130 blob_stream_.write(static_cast<const char *>(data), size);
131 current_offset_ += size;
133 return {blob_name_, {old_offset, size}};
134}
135
136static std::string make_independent_file_name(const StringRef base_name,
137 const int file_index,
138 const StringRef extension)
139{
140 return fmt::format("{}_file_{}{}", base_name, file_index, extension);
141}
142
144 const FunctionRef<void(std::ostream &)> fn)
145{
146 BLI_assert(file_extension.startswith("."));
147 independent_file_count_++;
148 const std::string file_name = make_independent_file_name(
149 base_name_, independent_file_count_, file_extension);
150
151 char path[FILE_MAX];
152 BLI_path_join(path, sizeof(path), blob_dir_.c_str(), file_name.c_str());
154 std::fstream stream{path, std::ios::out | std::ios::binary};
155 fn(stream);
156 const int64_t written_bytes_num = stream.tellg();
157 total_written_size_ += written_bytes_num;
158 return {file_name, {0, written_bytes_num}};
159}
160
162{
163 blob_by_name_.add(name, blob);
164}
165
166bool MemoryBlobReader::read(const BlobSlice &slice, void *r_data) const
167{
168 if (slice.range.is_empty()) {
169 return true;
170 }
171 const Span<std::byte> blob_data = blob_by_name_.lookup_default(slice.name, {});
172 if (!blob_data.index_range().contains(slice.range)) {
173 return false;
174 }
175 const void *copy_src = blob_data.slice(slice.range).data();
176 memcpy(r_data, copy_src, slice.range.size());
177 return true;
178}
179
180MemoryBlobWriter::MemoryBlobWriter(std::string base_name) : base_name_(std::move(base_name))
181{
182 blob_name_ = base_name_ + ".blob";
183 stream_by_name_.add(blob_name_, {std::make_unique<std::ostringstream>(std::ios::binary)});
184}
185
187{
188 OutputStream &stream = stream_by_name_.lookup(blob_name_);
189 const int64_t old_offset = stream.offset;
190 stream.stream->write(static_cast<const char *>(data), size);
191 stream.offset += size;
193 return {blob_name_, IndexRange::from_begin_size(old_offset, size)};
194}
195
197 const FunctionRef<void(std::ostream &)> fn)
198{
199 BLI_assert(file_extension.startswith("."));
200 independent_file_count_++;
201 const std::string name = make_independent_file_name(
202 base_name_, independent_file_count_, file_extension);
203 OutputStream stream{std::make_unique<std::ostringstream>(std::ios::binary)};
204 fn(*stream.stream);
205 const int64_t size = stream.stream->tellp();
206 stream_by_name_.add_new(name, std::move(stream));
208 return {base_name_, IndexRange(size)};
209}
210
212{
213 for (const ImplicitSharingInfo *sharing_info : stored_by_runtime_.keys()) {
214 sharing_info->remove_weak_user_and_delete_if_last();
215 }
216}
217
219{
220 for (const ImplicitSharingInfoAndData &value : runtime_by_stored_.values()) {
221 if (value.sharing_info) {
222 value.sharing_info->remove_user_and_delete_if_last();
223 }
224 }
225}
226
228 const ImplicitSharingInfo *sharing_info, FunctionRef<DictionaryValuePtr()> write_fn)
229{
230 if (sharing_info == nullptr) {
231 return write_fn();
232 }
233 return stored_by_runtime_.add_or_modify(
234 sharing_info,
235 /* Create new value. */
236 [&](StoredByRuntimeValue *value) {
237 new (value) StoredByRuntimeValue();
238 value->io_data = write_fn();
239 value->sharing_info_version = sharing_info->version();
240 sharing_info->add_weak_user();
241 return value->io_data;
242 },
243 /* Potentially modify existing value. */
244 [&](StoredByRuntimeValue *value) {
245 const int64_t new_version = sharing_info->version();
246 BLI_assert(value->sharing_info_version <= new_version);
247 if (value->sharing_info_version < new_version) {
248 value->io_data = write_fn();
249 value->sharing_info_version = new_version;
250 }
251 return value->io_data;
252 });
253}
254
255std::shared_ptr<io::serialize::DictionaryValue> BlobWriteSharing::write_deduplicated(
256 BlobWriter &writer, const void *data, const int64_t size_in_bytes)
257{
258 const uint64_t content_hash = XXH3_64bits(data, size_in_bytes);
259 const BlobSlice slice = slice_by_content_hash_.lookup_or_add_cb(
260 content_hash, [&]() { return writer.write(data, size_in_bytes); });
261 return slice.serialize();
262}
263
264std::optional<ImplicitSharingInfoAndData> BlobReadSharing::read_shared(
265 const DictionaryValue &io_data,
266 FunctionRef<std::optional<ImplicitSharingInfoAndData>()> read_fn) const
267{
268 std::lock_guard lock{mutex_};
269
271 std::stringstream ss;
272 formatter.serialize(ss, io_data);
273 const std::string key = ss.str();
274
275 if (const ImplicitSharingInfoAndData *shared_data = runtime_by_stored_.lookup_ptr(key)) {
276 shared_data->sharing_info->add_user();
277 return *shared_data;
278 }
279 std::optional<ImplicitSharingInfoAndData> data = read_fn();
280 if (!data) {
281 return std::nullopt;
282 }
283 if (data->sharing_info != nullptr) {
284 data->sharing_info->add_user();
285 runtime_by_stored_.add_new(key, *data);
286 }
287 return data;
288}
289
290static StringRefNull get_endian_io_name(const int endian)
291{
292 if (endian == L_ENDIAN) {
293 return "little";
294 }
295 BLI_assert(endian == B_ENDIAN);
296 return "big";
297}
298
300{
301 const char *io_name = "unknown";
303 return io_name;
304}
305
307{
308 const char *io_name = "unknown";
310 return io_name;
311}
312
313static std::optional<AttrDomain> get_domain_from_io_name(const StringRefNull io_name)
314{
315 int domain;
317 return std::nullopt;
318 }
319 return AttrDomain(domain);
320}
321
322static std::optional<eCustomDataType> get_data_type_from_io_name(const StringRefNull io_name)
323{
324 int domain;
326 return std::nullopt;
327 }
328 return eCustomDataType(domain);
329}
330
334static std::shared_ptr<DictionaryValue> write_blob_raw_data_with_endian(
335 BlobWriter &blob_writer,
336 BlobWriteSharing &blob_sharing,
337 const void *data,
338 const int64_t size_in_bytes)
339{
340 auto io_data = blob_sharing.write_deduplicated(blob_writer, data, size_in_bytes);
341 if (ENDIAN_ORDER == B_ENDIAN) {
342 io_data->append_str("endian", get_endian_io_name(ENDIAN_ORDER));
343 }
344 return io_data;
345}
346
350[[nodiscard]] static bool read_blob_raw_data_with_endian(const BlobReader &blob_reader,
351 const DictionaryValue &io_data,
352 const int64_t element_size,
353 const int64_t elements_num,
354 void *r_data)
355{
356 const std::optional<BlobSlice> slice = BlobSlice::deserialize(io_data);
357 if (!slice) {
358 return false;
359 }
360 if (slice->range.size() != element_size * elements_num) {
361 return false;
362 }
363 if (!blob_reader.read(*slice, r_data)) {
364 return false;
365 }
366 const StringRefNull stored_endian = io_data.lookup_str("endian").value_or("little");
367 const StringRefNull current_endian = get_endian_io_name(ENDIAN_ORDER);
368 const bool need_endian_switch = stored_endian != current_endian;
369 if (need_endian_switch) {
370 switch (element_size) {
371 case 1:
372 break;
373 case 2:
374 BLI_endian_switch_uint16_array(static_cast<uint16_t *>(r_data), elements_num);
375 break;
376 case 4:
377 BLI_endian_switch_uint32_array(static_cast<uint32_t *>(r_data), elements_num);
378 break;
379 case 8:
380 BLI_endian_switch_uint64_array(static_cast<uint64_t *>(r_data), elements_num);
381 break;
382 default:
383 return false;
384 }
385 }
386 return true;
387}
388
390static std::shared_ptr<DictionaryValue> write_blob_raw_bytes(BlobWriter &blob_writer,
391 BlobWriteSharing &blob_sharing,
392 const void *data,
393 const int64_t size_in_bytes)
394{
395 return blob_sharing.write_deduplicated(blob_writer, data, size_in_bytes);
396}
397
399[[nodiscard]] static bool read_blob_raw_bytes(const BlobReader &blob_reader,
400 const DictionaryValue &io_data,
401 const int64_t bytes_num,
402 void *r_data)
403{
404 const std::optional<BlobSlice> slice = BlobSlice::deserialize(io_data);
405 if (!slice) {
406 return false;
407 }
408 if (slice->range.size() != bytes_num) {
409 return false;
410 }
411 return blob_reader.read(*slice, r_data);
412}
413
414static std::shared_ptr<DictionaryValue> write_blob_simple_gspan(BlobWriter &blob_writer,
415 BlobWriteSharing &blob_sharing,
416 const GSpan data)
417{
418 const CPPType &type = data.type();
420 if (type.size == 1 || type.is<ColorGeometry4b>()) {
421 return write_blob_raw_bytes(blob_writer, blob_sharing, data.data(), data.size_in_bytes());
422 }
424 blob_writer, blob_sharing, data.data(), data.size_in_bytes());
425}
426
427[[nodiscard]] static bool read_blob_simple_gspan(const BlobReader &blob_reader,
428 const DictionaryValue &io_data,
429 GMutableSpan r_data)
430{
431 const CPPType &type = r_data.type();
433 if (type.size == 1 || type.is<ColorGeometry4b>()) {
434 return read_blob_raw_bytes(blob_reader, io_data, r_data.size_in_bytes(), r_data.data());
435 }
436 if (type.is_any<int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float>()) {
438 blob_reader, io_data, type.size, r_data.size(), r_data.data());
439 }
440 if (type.is_any<float2, int2>()) {
442 blob_reader, io_data, sizeof(int32_t), r_data.size() * 2, r_data.data());
443 }
444 if (type.is_any<short2>()) {
446 blob_reader, io_data, sizeof(short), r_data.size() * 2, r_data.data());
447 }
448 if (type.is<float3>()) {
450 blob_reader, io_data, sizeof(float), r_data.size() * 3, r_data.data());
451 }
452 if (type.is<float4x4>()) {
454 blob_reader, io_data, sizeof(float), r_data.size() * 16, r_data.data());
455 }
456 if (type.is<ColorGeometry4f>()) {
458 blob_reader, io_data, sizeof(float), r_data.size() * 4, r_data.data());
459 }
460 if (type.is<math::Quaternion>()) {
462 blob_reader, io_data, sizeof(float), r_data.size() * 4, r_data.data());
463 }
464 return false;
465}
466
467static std::shared_ptr<DictionaryValue> write_blob_shared_simple_gspan(
468 BlobWriter &blob_writer,
469 BlobWriteSharing &blob_sharing,
470 const GSpan data,
471 const ImplicitSharingInfo *sharing_info)
472{
473 return blob_sharing.write_implicitly_shared(
474 sharing_info, [&]() { return write_blob_simple_gspan(blob_writer, blob_sharing, data); });
475}
476
477[[nodiscard]] static const void *read_blob_shared_simple_gspan(
478 const DictionaryValue &io_data,
479 const BlobReader &blob_reader,
480 const BlobReadSharing &blob_sharing,
481 const CPPType &cpp_type,
482 const int size,
483 const ImplicitSharingInfo **r_sharing_info)
484{
485 const char *func = __func__;
486 const std::optional<ImplicitSharingInfoAndData> sharing_info_and_data = blob_sharing.read_shared(
487 io_data, [&]() -> std::optional<ImplicitSharingInfoAndData> {
488 void *data_mem = MEM_mallocN_aligned(size * cpp_type.size, cpp_type.alignment, func);
489 if (!read_blob_simple_gspan(blob_reader, io_data, {cpp_type, data_mem, size})) {
490 MEM_freeN(data_mem);
491 return std::nullopt;
492 }
494 });
495 if (!sharing_info_and_data) {
496 *r_sharing_info = nullptr;
497 return nullptr;
498 }
499 *r_sharing_info = sharing_info_and_data->sharing_info;
500 return sharing_info_and_data->data;
501}
502
503template<typename T>
504[[nodiscard]] static bool read_blob_shared_simple_span(const DictionaryValue &io_data,
505 const BlobReader &blob_reader,
506 const BlobReadSharing &blob_sharing,
507 const int size,
508 T **r_data,
509 const ImplicitSharingInfo **r_sharing_info)
510{
511 *r_data = const_cast<T *>(static_cast<const T *>(read_blob_shared_simple_gspan(
512 io_data, blob_reader, blob_sharing, CPPType::get<T>(), size, r_sharing_info)));
513 return *r_data != nullptr;
514}
515
516[[nodiscard]] static bool load_materials(const io::serialize::ArrayValue &io_materials,
517 std::unique_ptr<BakeMaterialsList> &materials)
518{
519 if (io_materials.elements().is_empty()) {
520 return true;
521 }
522 materials = std::make_unique<BakeMaterialsList>();
523 for (const auto &io_material_value : io_materials.elements()) {
524 if (io_material_value->type() == io::serialize::eValueType::Null) {
525 materials->append(std::nullopt);
526 continue;
527 }
528 const auto *io_material = io_material_value->as_dictionary_value();
529 if (!io_material) {
530 return false;
531 }
532 std::optional<std::string> id_name = io_material->lookup_str("name");
533 if (!id_name) {
534 return false;
535 }
536 std::string lib_name = io_material->lookup_str("lib_name").value_or("");
537 materials->append(BakeDataBlockID(ID_MA, std::move(*id_name), std::move(lib_name)));
538 }
539 return true;
540}
541
542[[nodiscard]] static bool load_attributes(const io::serialize::ArrayValue &io_attributes,
543 MutableAttributeAccessor &attributes,
544 const BlobReader &blob_reader,
545 const BlobReadSharing &blob_sharing)
546{
547 for (const auto &io_attribute_value : io_attributes.elements()) {
548 const auto *io_attribute = io_attribute_value->as_dictionary_value();
549 if (!io_attribute) {
550 return false;
551 }
552 const std::optional<StringRefNull> name = io_attribute->lookup_str("name");
553 const std::optional<StringRefNull> domain_str = io_attribute->lookup_str("domain");
554 const std::optional<StringRefNull> type_str = io_attribute->lookup_str("type");
555 const auto *io_data = io_attribute->lookup_dict("data");
556 if (!name || !domain_str || !type_str || !io_data) {
557 return false;
558 }
559
560 const std::optional<AttrDomain> domain = get_domain_from_io_name(*domain_str);
561 const std::optional<eCustomDataType> data_type = get_data_type_from_io_name(*type_str);
562 if (!domain || !data_type) {
563 return false;
564 }
565 const CPPType *cpp_type = custom_data_type_to_cpp_type(*data_type);
566 if (!cpp_type) {
567 return false;
568 }
569 const int domain_size = attributes.domain_size(*domain);
570 const ImplicitSharingInfo *attribute_sharing_info;
571 const void *attribute_data = read_blob_shared_simple_gspan(
572 *io_data, blob_reader, blob_sharing, *cpp_type, domain_size, &attribute_sharing_info);
573 if (!attribute_data) {
574 return false;
575 }
576 BLI_SCOPED_DEFER([&]() { attribute_sharing_info->remove_user_and_delete_if_last(); });
577
578 if (attributes.contains(*name)) {
579 /* If the attribute exists already, copy the values over to the existing array. */
581 *name, *domain, *data_type);
582 if (!attribute) {
583 return false;
584 }
585 cpp_type->copy_assign_n(attribute_data, attribute.span.data(), domain_size);
586 attribute.finish();
587 }
588 else {
589 /* Add a new attribute that shares the data. */
590 if (!attributes.add(*name,
591 *domain,
592 *data_type,
593 AttributeInitShared(attribute_data, *attribute_sharing_info)))
594 {
595 return false;
596 }
597 }
598 }
599 return true;
600}
601
603 const BlobReader &blob_reader,
604 const BlobReadSharing &blob_sharing)
605{
606 const DictionaryValue *io_pointcloud = io_geometry.lookup_dict("pointcloud");
607 if (!io_pointcloud) {
608 return nullptr;
609 }
610 const io::serialize::ArrayValue *io_attributes = io_pointcloud->lookup_array("attributes");
611 if (!io_attributes) {
612 return nullptr;
613 }
614 const int points_num = io_pointcloud->lookup_int("num_points").value_or(0);
615 PointCloud *pointcloud = bke::pointcloud_new_no_attributes(points_num);
616
617 auto cancel = [&]() {
618 BKE_id_free(nullptr, pointcloud);
619 return nullptr;
620 };
621
622 MutableAttributeAccessor attributes = pointcloud->attributes_for_write();
623 if (!load_attributes(*io_attributes, attributes, blob_reader, blob_sharing)) {
624 return cancel();
625 }
626
627 if (const io::serialize::ArrayValue *io_materials = io_pointcloud->lookup_array("materials")) {
628 if (!load_materials(*io_materials, pointcloud->runtime->bake_materials)) {
629 return cancel();
630 }
631 }
632 return pointcloud;
633}
634
635static std::optional<CurvesGeometry> try_load_curves_geometry(const DictionaryValue &io_curves,
636 const BlobReader &blob_reader,
637 const BlobReadSharing &blob_sharing)
638{
639 const io::serialize::ArrayValue *io_attributes = io_curves.lookup_array("attributes");
640 if (!io_attributes) {
641 return std::nullopt;
642 }
643
645 CustomData_free_layer_named(&curves.point_data, "position");
646 curves.point_num = io_curves.lookup_int("num_points").value_or(0);
647 curves.curve_num = io_curves.lookup_int("num_curves").value_or(0);
648
649 if (curves.curves_num() > 0) {
650 const auto *io_curve_offsets = io_curves.lookup_dict("curve_offsets");
651 if (!io_curve_offsets) {
652 return std::nullopt;
653 }
654 if (!read_blob_shared_simple_span(*io_curve_offsets,
655 blob_reader,
656 blob_sharing,
657 curves.curves_num() + 1,
658 &curves.curve_offsets,
659 &curves.runtime->curve_offsets_sharing_info))
660 {
661 return std::nullopt;
662 }
663 }
664
665 MutableAttributeAccessor attributes = curves.attributes_for_write();
666 if (!load_attributes(*io_attributes, attributes, blob_reader, blob_sharing)) {
667 return std::nullopt;
668 }
669
670 if (const io::serialize::ArrayValue *io_materials = io_curves.lookup_array("materials")) {
671 if (!load_materials(*io_materials, curves.runtime->bake_materials)) {
672 return std::nullopt;
673 }
674 }
675
676 curves.update_curve_types();
677 return curves;
678}
679
680static Curves *try_load_curves(const DictionaryValue &io_geometry,
681 const BlobReader &blob_reader,
682 const BlobReadSharing &blob_sharing)
683{
684 const DictionaryValue *io_curves = io_geometry.lookup_dict("curves");
685 if (!io_curves) {
686 return nullptr;
687 }
688
689 const io::serialize::ArrayValue *io_attributes = io_curves->lookup_array("attributes");
690 if (!io_attributes) {
691 return nullptr;
692 }
693
694 std::optional<CurvesGeometry> curves_opt = try_load_curves_geometry(
695 *io_curves, blob_reader, blob_sharing);
696 if (!curves_opt) {
697 return nullptr;
698 }
699
700 Curves *curves_id = curves_new_nomain(std::move(*curves_opt));
701 CurvesGeometry &curves = curves_id->geometry.wrap();
702
703 auto cancel = [&]() {
704 BKE_id_free(nullptr, curves_id);
705 return nullptr;
706 };
707
708 if (const io::serialize::ArrayValue *io_materials = io_curves->lookup_array("materials")) {
709 if (!load_materials(*io_materials, curves.runtime->bake_materials)) {
710 return cancel();
711 }
712 }
713
714 return curves_id;
715}
716
718 const BlobReader &blob_reader,
719 const BlobReadSharing &blob_sharing)
720{
721 const DictionaryValue *io_grease_pencil = io_geometry.lookup_dict("grease_pencil");
722 if (!io_grease_pencil) {
723 return nullptr;
724 }
725
726 const io::serialize::ArrayValue *io_layers = io_grease_pencil->lookup_array("layers");
727 if (!io_layers) {
728 return nullptr;
729 }
730
731 const io::serialize::ArrayValue *io_layer_attributes = io_grease_pencil->lookup_array(
732 "layer_attributes");
733 if (!io_layer_attributes) {
734 return nullptr;
735 }
736
738 auto cancel = [&]() {
739 BKE_id_free(nullptr, grease_pencil);
740 return nullptr;
741 };
742
743 const int layers_num = io_layers->elements().size();
744 grease_pencil->add_layers_with_empty_drawings_for_eval(layers_num);
745
746 for (const int layer_i : io_layers->elements().index_range()) {
747 const auto &io_layer_value = io_layers->elements()[layer_i];
748 const io::serialize::DictionaryValue *io_layer = io_layer_value->as_dictionary_value();
749 if (!io_layer) {
750 return cancel();
751 }
752 const io::serialize::DictionaryValue *io_strokes = io_layer->lookup_dict("strokes");
753 if (!io_strokes) {
754 return cancel();
755 }
756 const std::optional<std::string> layer_name = io_layer->lookup_str("name");
757 if (!layer_name) {
758 return cancel();
759 }
760 greasepencil::Layer &layer = grease_pencil->layer(layer_i);
761 layer.set_name(*layer_name);
762 std::optional<CurvesGeometry> curves_opt = try_load_curves_geometry(
763 *io_strokes, blob_reader, blob_sharing);
764 if (!curves_opt) {
765 return cancel();
766 }
767 greasepencil::Drawing &drawing = *grease_pencil->get_eval_drawing(layer);
768 drawing.strokes_for_write() = std::move(*curves_opt);
769 }
770
771 MutableAttributeAccessor attributes = grease_pencil->attributes_for_write();
772 if (!load_attributes(*io_layer_attributes, attributes, blob_reader, blob_sharing)) {
773 return cancel();
774 }
775
776 const DictionaryValue *io_layer_opacities = io_grease_pencil->lookup_dict("opacities");
777 Array<float> layer_opacities(layers_num);
778 if (!io_layer_opacities ||
779 !read_blob_simple_gspan(blob_reader, *io_layer_opacities, layer_opacities.as_mutable_span()))
780 {
781 return cancel();
782 }
783
784 const DictionaryValue *io_layer_blend_modes = io_grease_pencil->lookup_dict("blend_modes");
785 Array<int8_t> layer_blend_modes(layers_num);
786 if (!io_layer_opacities || !read_blob_simple_gspan(blob_reader,
787 *io_layer_blend_modes,
788 layer_blend_modes.as_mutable_span()))
789 {
790 return cancel();
791 }
792
793 const DictionaryValue *io_layer_transforms = io_grease_pencil->lookup_dict("transforms");
794 Array<float4x4> layer_transforms(layers_num);
795 if (!io_layer_transforms || !read_blob_simple_gspan(blob_reader,
796 *io_layer_transforms,
797 layer_transforms.as_mutable_span()))
798 {
799 return cancel();
800 }
801
802 for (const int layer_i : IndexRange(layers_num)) {
803 greasepencil::Layer &layer = grease_pencil->layer(layer_i);
804 layer.opacity = layer_opacities[layer_i];
805 layer.blend_mode = layer_blend_modes[layer_i];
806 layer.set_local_transform(layer_transforms[layer_i]);
807 }
808
809 if (const io::serialize::ArrayValue *io_materials = io_grease_pencil->lookup_array("materials"))
810 {
811 if (!load_materials(*io_materials, grease_pencil->runtime->bake_materials)) {
812 return cancel();
813 }
814 }
815
816 return grease_pencil;
817}
818
819static Mesh *try_load_mesh(const DictionaryValue &io_geometry,
820 const BlobReader &blob_reader,
821 const BlobReadSharing &blob_sharing)
822{
823 const DictionaryValue *io_mesh = io_geometry.lookup_dict("mesh");
824 if (!io_mesh) {
825 return nullptr;
826 }
827
828 const io::serialize::ArrayValue *io_attributes = io_mesh->lookup_array("attributes");
829 if (!io_attributes) {
830 return nullptr;
831 }
832
833 Mesh *mesh = BKE_mesh_new_nomain(0, 0, 0, 0);
834 CustomData_free_layer_named(&mesh->vert_data, "position");
835 CustomData_free_layer_named(&mesh->edge_data, ".edge_verts");
836 CustomData_free_layer_named(&mesh->corner_data, ".corner_vert");
837 CustomData_free_layer_named(&mesh->corner_data, ".corner_edge");
838 mesh->verts_num = io_mesh->lookup_int("num_vertices").value_or(0);
839 mesh->edges_num = io_mesh->lookup_int("num_edges").value_or(0);
840 mesh->faces_num = io_mesh->lookup_int("num_polygons").value_or(0);
841 mesh->corners_num = io_mesh->lookup_int("num_corners").value_or(0);
842
843 auto cancel = [&]() {
844 BKE_id_free(nullptr, mesh);
845 return nullptr;
846 };
847
848 if (mesh->faces_num > 0) {
849 const auto *io_poly_offsets = io_mesh->lookup_dict("poly_offsets");
850 if (!io_poly_offsets) {
851 return cancel();
852 }
853 if (!read_blob_shared_simple_span(*io_poly_offsets,
854 blob_reader,
855 blob_sharing,
856 mesh->faces_num + 1,
857 &mesh->face_offset_indices,
858 &mesh->runtime->face_offsets_sharing_info))
859 {
860 return cancel();
861 }
862 }
863
864 /* Create the vertex group name list, then later on when processing generic attributes, these
865 * names will be stored as vertex groups. */
866 if (const auto *io_attributes = io_mesh->lookup_array("vertex_group_names")) {
867 for (const std::shared_ptr<Value> &value : io_attributes->elements()) {
868 if (value->type() != io::serialize::eValueType::String) {
869 return cancel();
870 }
871 bDeformGroup *defgroup = MEM_callocN<bDeformGroup>(__func__);
872 STRNCPY(defgroup->name, value->as_string_value()->value().c_str());
873 BLI_addtail(&mesh->vertex_group_names, defgroup);
874 }
875 }
876
877 MutableAttributeAccessor attributes = mesh->attributes_for_write();
878 if (!load_attributes(*io_attributes, attributes, blob_reader, blob_sharing)) {
879 return cancel();
880 }
881
882 if (const io::serialize::ArrayValue *io_materials = io_mesh->lookup_array("materials")) {
883 if (!load_materials(*io_materials, mesh->runtime->bake_materials)) {
884 return cancel();
885 }
886 }
887
888 return mesh;
889}
890
891static GeometrySet load_geometry(const DictionaryValue &io_geometry,
892 const BlobReader &blob_reader,
893 const BlobReadSharing &blob_sharing);
894
895static std::unique_ptr<Instances> try_load_instances(const DictionaryValue &io_geometry,
896 const BlobReader &blob_reader,
897 const BlobReadSharing &blob_sharing)
898{
899 const DictionaryValue *io_instances = io_geometry.lookup_dict("instances");
900 if (!io_instances) {
901 return nullptr;
902 }
903 const int num_instances = io_instances->lookup_int("num_instances").value_or(0);
904 if (num_instances == 0) {
905 return nullptr;
906 }
907 const io::serialize::ArrayValue *io_attributes = io_instances->lookup_array("attributes");
908 if (!io_attributes) {
909 return nullptr;
910 }
911 const io::serialize::ArrayValue *io_references = io_instances->lookup_array("references");
912 if (!io_references) {
913 return nullptr;
914 }
915
916 std::unique_ptr<Instances> instances = std::make_unique<Instances>();
917 instances->resize(num_instances);
918
919 for (const auto &io_reference_value : io_references->elements()) {
920 const DictionaryValue *io_reference = io_reference_value->as_dictionary_value();
921 GeometrySet reference_geometry;
922 if (io_reference) {
923 reference_geometry = load_geometry(*io_reference, blob_reader, blob_sharing);
924 }
925 instances->add_new_reference(std::move(reference_geometry));
926 }
927
928 MutableAttributeAccessor attributes = instances->attributes_for_write();
929 if (!load_attributes(*io_attributes, attributes, blob_reader, blob_sharing)) {
930 return {};
931 }
932
933 if (!attributes.contains(".reference_index")) {
934 /* Try reading the reference index attribute from the old bake format from before it was an
935 * attribute. */
936 const auto *io_handles = io_instances->lookup_dict("handles");
937 if (!io_handles) {
938 return {};
939 }
941 blob_reader, *io_handles, instances->reference_handles_for_write()))
942 {
943 return {};
944 }
945 }
946
947 if (!attributes.contains("instance_transform")) {
948 /* Try reading the transform attribute from the old bake format from before it was an
949 * attribute. */
950 const auto *io_handles = io_instances->lookup_dict("transforms");
951 if (!io_handles) {
952 return {};
953 }
954 if (!read_blob_simple_gspan(blob_reader, *io_handles, instances->transforms_for_write())) {
955 return {};
956 }
957 }
958
959 return instances;
960}
961
962#ifdef WITH_OPENVDB
963static Volume *try_load_volume(const DictionaryValue &io_geometry, const BlobReader &blob_reader)
964{
965 const DictionaryValue *io_volume = io_geometry.lookup_dict("volume");
966 if (!io_volume) {
967 return nullptr;
968 }
969 const auto *io_vdb = io_volume->lookup_dict("vdb");
970 if (!io_vdb) {
971 return nullptr;
972 }
973 openvdb::GridPtrVecPtr vdb_grids;
974 if (std::optional<BlobSlice> vdb_slice = BlobSlice::deserialize(*io_vdb)) {
975 if (!blob_reader.read_as_stream(*vdb_slice, [&](std::istream &stream) {
976 try {
977 openvdb::io::Stream vdb_stream{stream};
978 vdb_grids = vdb_stream.getGrids();
979 return true;
980 }
981 catch (...) {
982 return false;
983 }
984 }))
985 {
986 return nullptr;
987 }
988 }
989 Volume *volume = BKE_id_new_nomain<Volume>(nullptr);
990 auto cancel = [&]() {
991 BKE_id_free(nullptr, volume);
992 return nullptr;
993 };
994
995 for (openvdb::GridBase::Ptr &vdb_grid : *vdb_grids) {
996 if (vdb_grid) {
997 bke::GVolumeGrid grid{std::move(vdb_grid)};
998 BKE_volume_grid_add(volume, *grid.release());
999 }
1000 }
1001 if (const io::serialize::ArrayValue *io_materials = io_volume->lookup_array("materials")) {
1002 if (!load_materials(*io_materials, volume->runtime->bake_materials)) {
1003 return cancel();
1004 }
1005 }
1006 return volume;
1007}
1008#endif
1009
1011 const BlobReader &blob_reader,
1012 const BlobReadSharing &blob_sharing)
1013{
1015 geometry.replace_mesh(try_load_mesh(io_geometry, blob_reader, blob_sharing));
1016 geometry.replace_pointcloud(try_load_pointcloud(io_geometry, blob_reader, blob_sharing));
1017 geometry.replace_curves(try_load_curves(io_geometry, blob_reader, blob_sharing));
1018 geometry.replace_grease_pencil(try_load_grease_pencil(io_geometry, blob_reader, blob_sharing));
1019 geometry.replace_instances(try_load_instances(io_geometry, blob_reader, blob_sharing).release());
1020#ifdef WITH_OPENVDB
1021 geometry.replace_volume(try_load_volume(io_geometry, blob_reader));
1022#endif
1023 return geometry;
1024}
1025
1026static std::shared_ptr<io::serialize::ArrayValue> serialize_materials(
1027 const std::unique_ptr<BakeMaterialsList> &materials)
1028{
1029 auto io_materials = std::make_shared<io::serialize::ArrayValue>();
1030 if (!materials) {
1031 return io_materials;
1032 }
1033 for (const std::optional<BakeDataBlockID> &material : *materials) {
1034 if (material) {
1035 auto io_material = io_materials->append_dict();
1036 io_material->append_str("name", material->id_name);
1037 if (!material->lib_name.empty()) {
1038 io_material->append_str("lib_name", material->lib_name);
1039 }
1040 }
1041 else {
1042 io_materials->append_null();
1043 }
1044 }
1045 return io_materials;
1046}
1047
1048static std::shared_ptr<io::serialize::ArrayValue> serialize_attributes(
1049 const AttributeAccessor &attributes,
1050 BlobWriter &blob_writer,
1051 BlobWriteSharing &blob_sharing,
1052 const Set<std::string> &attributes_to_ignore)
1053{
1054 auto io_attributes = std::make_shared<io::serialize::ArrayValue>();
1055 attributes.foreach_attribute([&](const AttributeIter &iter) {
1057 if (attributes_to_ignore.contains_as(iter.name)) {
1058 return;
1059 }
1060
1061 auto io_attribute = io_attributes->append_dict();
1062
1063 io_attribute->append_str("name", iter.name);
1064
1065 const StringRefNull domain_name = get_domain_io_name(iter.domain);
1066 io_attribute->append_str("domain", domain_name);
1067
1068 const StringRefNull type_name = get_data_type_io_name(iter.data_type);
1069 io_attribute->append_str("type", type_name);
1070
1071 const GAttributeReader attribute = iter.get();
1072 const GVArraySpan attribute_span(attribute.varray);
1073 io_attribute->append("data",
1075 blob_writer,
1076 blob_sharing,
1077 attribute_span,
1078 attribute.varray.is_span() ? attribute.sharing_info : nullptr));
1079 });
1080 return io_attributes;
1081}
1082
1084 const CurvesGeometry &curves,
1085 BlobWriter &blob_writer,
1086 BlobWriteSharing &blob_sharing)
1087{
1088 io_curves.append_int("num_points", curves.point_num);
1089 io_curves.append_int("num_curves", curves.curve_num);
1090
1091 if (curves.curve_num > 0) {
1092 io_curves.append("curve_offsets",
1094 blob_sharing,
1095 curves.offsets(),
1096 curves.runtime->curve_offsets_sharing_info));
1097 }
1098
1099 auto io_attributes = serialize_attributes(curves.attributes(), blob_writer, blob_sharing, {});
1100 io_curves.append("attributes", io_attributes);
1101}
1102
1103static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet &geometry,
1104 BlobWriter &blob_writer,
1105 BlobWriteSharing &blob_sharing)
1106{
1107 auto io_geometry = std::make_shared<DictionaryValue>();
1108 if (geometry.has_mesh()) {
1109 const Mesh &mesh = *geometry.get_mesh();
1110 auto io_mesh = io_geometry->append_dict("mesh");
1111
1112 io_mesh->append_int("num_vertices", mesh.verts_num);
1113 io_mesh->append_int("num_edges", mesh.edges_num);
1114 io_mesh->append_int("num_polygons", mesh.faces_num);
1115 io_mesh->append_int("num_corners", mesh.corners_num);
1116
1117 if (mesh.faces_num > 0) {
1118 io_mesh->append("poly_offsets",
1120 blob_sharing,
1121 mesh.face_offsets(),
1122 mesh.runtime->face_offsets_sharing_info));
1123 }
1124
1125 auto io_materials = serialize_materials(mesh.runtime->bake_materials);
1126 io_mesh->append("materials", io_materials);
1127
1128 if (!BLI_listbase_is_empty(&mesh.vertex_group_names)) {
1129 auto io_vertex_group_names = io_mesh->append_array("vertex_group_names");
1130 LISTBASE_FOREACH (bDeformGroup *, defgroup, &mesh.vertex_group_names) {
1131 io_vertex_group_names->append_str(defgroup->name);
1132 }
1133 }
1134
1135 auto io_attributes = serialize_attributes(mesh.attributes(), blob_writer, blob_sharing, {});
1136 io_mesh->append("attributes", io_attributes);
1137 }
1138 if (geometry.has_pointcloud()) {
1139 const PointCloud &pointcloud = *geometry.get_pointcloud();
1140 auto io_pointcloud = io_geometry->append_dict("pointcloud");
1141
1142 io_pointcloud->append_int("num_points", pointcloud.totpoint);
1143
1144 auto io_materials = serialize_materials(pointcloud.runtime->bake_materials);
1145 io_pointcloud->append("materials", io_materials);
1146
1147 auto io_attributes = serialize_attributes(
1148 pointcloud.attributes(), blob_writer, blob_sharing, {});
1149 io_pointcloud->append("attributes", io_attributes);
1150 }
1151 if (geometry.has_curves()) {
1152 const Curves &curves_id = *geometry.get_curves();
1153 const CurvesGeometry &curves = curves_id.geometry.wrap();
1154
1155 auto io_curves = io_geometry->append_dict("curves");
1156
1157 serialize_curves_geometry(*io_curves, curves, blob_writer, blob_sharing);
1158
1159 auto io_materials = serialize_materials(curves.runtime->bake_materials);
1160 io_curves->append("materials", io_materials);
1161 }
1162 if (geometry.has_grease_pencil()) {
1163 const GreasePencil &grease_pencil = *geometry.get_grease_pencil();
1164 auto io_grease_pencil = io_geometry->append_dict("grease_pencil");
1165 auto io_layers = io_grease_pencil->append_array("layers");
1166
1167 Vector<float> layer_opacities;
1168 Vector<int8_t> layer_blend_modes;
1169 Vector<float4x4> layer_transforms;
1170 for (const greasepencil::Layer *layer : grease_pencil.layers()) {
1171 auto io_layer = io_layers->append_dict();
1172 io_layer->append_str("name", layer->name());
1173 auto io_strokes = io_layer->append_dict("strokes");
1174 const greasepencil::Drawing *drawing = grease_pencil.get_eval_drawing(*layer);
1175 if (drawing) {
1176 serialize_curves_geometry(*io_strokes, drawing->strokes(), blob_writer, blob_sharing);
1177 }
1178 else {
1179 serialize_curves_geometry(*io_strokes, CurvesGeometry(), blob_writer, blob_sharing);
1180 }
1181
1182 layer_opacities.append(layer->opacity);
1183 layer_blend_modes.append(layer->blend_mode);
1184 layer_transforms.append(layer->local_transform());
1185 }
1186
1187 io_grease_pencil->append(
1188 "opacities",
1189 write_blob_simple_gspan(blob_writer, blob_sharing, layer_opacities.as_span()));
1190 io_grease_pencil->append(
1191 "blend_modes",
1192 write_blob_simple_gspan(blob_writer, blob_sharing, layer_blend_modes.as_span()));
1193 io_grease_pencil->append(
1194 "transforms",
1195 write_blob_simple_gspan(blob_writer, blob_sharing, layer_transforms.as_span()));
1196
1197 auto io_layer_attributes = serialize_attributes(
1198 grease_pencil.attributes(), blob_writer, blob_sharing, {});
1199 io_grease_pencil->append("layer_attributes", io_layer_attributes);
1200
1201 auto io_materials = serialize_materials(grease_pencil.runtime->bake_materials);
1202 io_grease_pencil->append("materials", io_materials);
1203 }
1204#ifdef WITH_OPENVDB
1205 if (geometry.has_volume()) {
1206 const Volume &volume = *geometry.get_volume();
1207 const int grids_num = BKE_volume_num_grids(&volume);
1208
1209 auto io_volume = io_geometry->append_dict("volume");
1210 auto io_vdb = blob_writer
1211 .write_as_stream(".vdb",
1212 [&](std::ostream &stream) {
1213 openvdb::GridCPtrVec vdb_grids;
1215 for (const int i : IndexRange(grids_num)) {
1216 const bke::VolumeGridData *grid = BKE_volume_grid_get(
1217 &volume, i);
1218 tree_tokens.append_as();
1219 vdb_grids.push_back(grid->grid_ptr(tree_tokens.last()));
1220 }
1221
1222 openvdb::io::Stream vdb_stream(stream);
1223 vdb_stream.write(vdb_grids);
1224 })
1225 .serialize();
1226 io_volume->append("vdb", std::move(io_vdb));
1227
1228 auto io_materials = serialize_materials(volume.runtime->bake_materials);
1229 io_volume->append("materials", io_materials);
1230 }
1231#endif
1232 if (geometry.has_instances()) {
1233 const Instances &instances = *geometry.get_instances();
1234 auto io_instances = io_geometry->append_dict("instances");
1235
1236 io_instances->append_int("num_instances", instances.instances_num());
1237
1238 auto io_references = io_instances->append_array("references");
1239 for (const InstanceReference &reference : instances.references()) {
1240 if (reference.type() == InstanceReference::Type::GeometrySet) {
1241 const GeometrySet &geometry = reference.geometry_set();
1242 io_references->append(serialize_geometry_set(geometry, blob_writer, blob_sharing));
1243 }
1244 else {
1245 /* TODO: Support serializing object and collection references. */
1246 io_references->append(serialize_geometry_set({}, blob_writer, blob_sharing));
1247 }
1248 }
1249
1250 auto io_attributes = serialize_attributes(
1251 instances.attributes(), blob_writer, blob_sharing, {});
1252 io_instances->append("attributes", io_attributes);
1253 }
1254 return io_geometry;
1255}
1256
1257static std::shared_ptr<io::serialize::ArrayValue> serialize_float_array(const Span<float> values)
1258{
1259 auto io_value = std::make_shared<io::serialize::ArrayValue>();
1260 for (const float value : values) {
1261 io_value->append_double(value);
1262 }
1263 return io_value;
1264}
1265
1266static std::shared_ptr<io::serialize::ArrayValue> serialize_int_array(const Span<int> values)
1267{
1268 auto io_value = std::make_shared<io::serialize::ArrayValue>();
1269 for (const int value : values) {
1270 io_value->append_int(value);
1271 }
1272 return io_value;
1273}
1274
1275static std::shared_ptr<io::serialize::Value> serialize_primitive_value(
1276 const eCustomDataType data_type, const void *value_ptr)
1277{
1278 switch (data_type) {
1279 case CD_PROP_FLOAT: {
1280 const float value = *static_cast<const float *>(value_ptr);
1281 return std::make_shared<io::serialize::DoubleValue>(value);
1282 }
1283 case CD_PROP_FLOAT2: {
1284 const float2 value = *static_cast<const float2 *>(value_ptr);
1285 return serialize_float_array({&value.x, 2});
1286 }
1287 case CD_PROP_FLOAT3: {
1288 const float3 value = *static_cast<const float3 *>(value_ptr);
1289 return serialize_float_array({&value.x, 3});
1290 }
1291 case CD_PROP_BOOL: {
1292 const bool value = *static_cast<const bool *>(value_ptr);
1293 return std::make_shared<io::serialize::BooleanValue>(value);
1294 }
1295 case CD_PROP_INT32: {
1296 const int value = *static_cast<const int *>(value_ptr);
1297 return std::make_shared<io::serialize::IntValue>(value);
1298 }
1299 case CD_PROP_INT16_2D: {
1300 const int2 value = int2(*static_cast<const short2 *>(value_ptr));
1301 return serialize_int_array({&value.x, 2});
1302 }
1303 case CD_PROP_INT32_2D: {
1304 const int2 value = *static_cast<const int2 *>(value_ptr);
1305 return serialize_int_array({&value.x, 2});
1306 }
1307 case CD_PROP_BYTE_COLOR: {
1308 const ColorGeometry4b value = *static_cast<const ColorGeometry4b *>(value_ptr);
1309 const int4 value_int{&value.r};
1310 return serialize_int_array({&value_int.x, 4});
1311 }
1312 case CD_PROP_COLOR: {
1313 const ColorGeometry4f value = *static_cast<const ColorGeometry4f *>(value_ptr);
1314 return serialize_float_array({&value.r, 4});
1315 }
1316 case CD_PROP_QUATERNION: {
1317 const math::Quaternion value = *static_cast<const math::Quaternion *>(value_ptr);
1318 return serialize_float_array({&value.w, 4});
1319 }
1320 case CD_PROP_FLOAT4X4: {
1321 const float4x4 value = *static_cast<const float4x4 *>(value_ptr);
1323 }
1324 default:
1325 break;
1326 }
1328 return {};
1329}
1330
1331template<typename T>
1332[[nodiscard]] static bool deserialize_typed_array(
1333 const io::serialize::Value &io_value,
1334 FunctionRef<std::optional<T>(const io::serialize::Value &io_element)> fn,
1335 MutableSpan<T> r_values)
1336{
1337 const io::serialize::ArrayValue *io_array = io_value.as_array_value();
1338 if (!io_array) {
1339 return false;
1340 }
1341 if (io_array->elements().size() != r_values.size()) {
1342 return false;
1343 }
1344 for (const int i : r_values.index_range()) {
1345 const io::serialize::Value &io_element = *io_array->elements()[i];
1346 std::optional<T> element = fn(io_element);
1347 if (!element) {
1348 return false;
1349 }
1350 r_values[i] = std::move(*element);
1351 }
1352 return true;
1353}
1354
1355template<typename T> static std::optional<T> deserialize_int(const io::serialize::Value &io_value)
1356{
1357 const io::serialize::IntValue *io_int = io_value.as_int_value();
1358 if (!io_int) {
1359 return std::nullopt;
1360 }
1361 const int64_t value = io_int->value();
1362 if (value < std::numeric_limits<T>::lowest()) {
1363 return std::nullopt;
1364 }
1365 if (value > std::numeric_limits<T>::max()) {
1366 return std::nullopt;
1367 }
1368 return value;
1369}
1370
1371static std::optional<float> deserialize_float(const io::serialize::Value &io_value)
1372{
1373 if (const io::serialize::DoubleValue *io_double = io_value.as_double_value()) {
1374 return io_double->value();
1375 }
1376 if (const io::serialize::IntValue *io_int = io_value.as_int_value()) {
1377 return io_int->value();
1378 }
1379 return std::nullopt;
1380}
1381
1382[[nodiscard]] static bool deserialize_float_array(const io::serialize::Value &io_value,
1383 MutableSpan<float> r_values)
1384{
1385 return deserialize_typed_array<float>(io_value, deserialize_float, r_values);
1386}
1387
1388template<typename T>
1389[[nodiscard]] static bool deserialize_int_array(const io::serialize::Value &io_value,
1390 MutableSpan<T> r_values)
1391{
1392 static_assert(std::is_integral_v<T>);
1393 return deserialize_typed_array<T>(io_value, deserialize_int<T>, r_values);
1394}
1395
1396[[nodiscard]] static bool deserialize_primitive_value(const io::serialize::Value &io_value,
1397 const eCustomDataType type,
1398 void *r_value)
1399{
1400 switch (type) {
1401 case CD_PROP_FLOAT: {
1402 const std::optional<float> value = deserialize_float(io_value);
1403 if (!value) {
1404 return false;
1405 }
1406 *static_cast<float *>(r_value) = *value;
1407 return true;
1408 }
1409 case CD_PROP_FLOAT2: {
1410 return deserialize_float_array(io_value, {static_cast<float *>(r_value), 2});
1411 }
1412 case CD_PROP_FLOAT3: {
1413 return deserialize_float_array(io_value, {static_cast<float *>(r_value), 3});
1414 }
1415 case CD_PROP_BOOL: {
1416 if (const io::serialize::BooleanValue *io_value_boolean = io_value.as_boolean_value()) {
1417 *static_cast<bool *>(r_value) = io_value_boolean->value();
1418 return true;
1419 }
1420 return false;
1421 }
1422 case CD_PROP_INT32: {
1423 const std::optional<int> value = deserialize_int<int>(io_value);
1424 if (!value) {
1425 return false;
1426 }
1427 *static_cast<int *>(r_value) = *value;
1428 return true;
1429 }
1430 case CD_PROP_INT16_2D: {
1431 return deserialize_int_array<int16_t>(io_value, {static_cast<int16_t *>(r_value), 2});
1432 }
1433 case CD_PROP_INT32_2D: {
1434 return deserialize_int_array<int>(io_value, {static_cast<int *>(r_value), 2});
1435 }
1436 case CD_PROP_BYTE_COLOR: {
1437 return deserialize_int_array<uint8_t>(io_value, {static_cast<uint8_t *>(r_value), 4});
1438 }
1439 case CD_PROP_COLOR: {
1440 return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4});
1441 }
1442 case CD_PROP_QUATERNION: {
1443 return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4});
1444 }
1445 case CD_PROP_FLOAT4X4: {
1446 return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4 * 4});
1447 }
1448 default:
1449 break;
1450 }
1451 return false;
1452}
1453
1454static void serialize_bake_item(const BakeItem &item,
1455 BlobWriter &blob_writer,
1456 BlobWriteSharing &blob_sharing,
1457 DictionaryValue &r_io_item)
1458{
1459 if (!item.name.empty()) {
1460 r_io_item.append_str("name", item.name);
1461 }
1462 if (const auto *geometry_state_item = dynamic_cast<const GeometryBakeItem *>(&item)) {
1463 r_io_item.append_str("type", "GEOMETRY");
1464
1465 const GeometrySet &geometry = geometry_state_item->geometry;
1466 auto io_geometry = serialize_geometry_set(geometry, blob_writer, blob_sharing);
1467 r_io_item.append("data", io_geometry);
1468 }
1469 else if (const auto *attribute_state_item = dynamic_cast<const AttributeBakeItem *>(&item)) {
1470 r_io_item.append_str("type", "ATTRIBUTE");
1471 r_io_item.append_str("name", attribute_state_item->name());
1472 }
1473#ifdef WITH_OPENVDB
1474 else if (const auto *grid_state_item = dynamic_cast<const VolumeGridBakeItem *>(&item)) {
1475 r_io_item.append_str("type", "GRID");
1476 const GVolumeGrid &grid = *grid_state_item->grid;
1477 auto io_vdb = blob_writer
1478 .write_as_stream(".vdb",
1479 [&](std::ostream &stream) {
1480 openvdb::GridCPtrVec vdb_grids;
1481 bke::VolumeTreeAccessToken tree_token;
1482 vdb_grids.push_back(grid->grid_ptr(tree_token));
1483 openvdb::io::Stream vdb_stream(stream);
1484 vdb_stream.write(vdb_grids);
1485 })
1486 .serialize();
1487 r_io_item.append("vdb", std::move(io_vdb));
1488 }
1489#endif
1490 else if (const auto *string_state_item = dynamic_cast<const StringBakeItem *>(&item)) {
1491 r_io_item.append_str("type", "STRING");
1492 const StringRefNull str = string_state_item->value();
1493 /* Small strings are inlined, larger strings are stored separately. */
1494 const int64_t blob_threshold = 100;
1495 if (str.size() < blob_threshold) {
1496 r_io_item.append_str("data", string_state_item->value());
1497 }
1498 else {
1499 r_io_item.append("data",
1500 write_blob_raw_bytes(blob_writer, blob_sharing, str.data(), str.size()));
1501 }
1502 }
1503 else if (const auto *primitive_state_item = dynamic_cast<const PrimitiveBakeItem *>(&item)) {
1504 const eCustomDataType data_type = cpp_type_to_custom_data_type(primitive_state_item->type());
1505 r_io_item.append_str("type", get_data_type_io_name(data_type));
1506 auto io_data = serialize_primitive_value(data_type, primitive_state_item->value());
1507 r_io_item.append("data", std::move(io_data));
1508 }
1509 else if (const auto *bundle_state_item = dynamic_cast<const BundleBakeItem *>(&item)) {
1510 r_io_item.append_str("type", "BUNDLE");
1511 ArrayValue &io_items = *r_io_item.append_array("items");
1512 for (const BundleBakeItem::Item &item : bundle_state_item->items) {
1513 DictionaryValue &io_bundle_item = *io_items.append_dict();
1514 ArrayValue &io_key = *io_bundle_item.append_array("key");
1515 for (const std::string &identifier : item.key.identifiers()) {
1516 io_key.append_str(identifier);
1517 }
1518 io_bundle_item.append_str("socket_idname", item.socket_idname);
1519 io::serialize::DictionaryValue &io_bundle_item_value = *io_bundle_item.append_dict("value");
1520 serialize_bake_item(*item.value, blob_writer, blob_sharing, io_bundle_item_value);
1521 }
1522 }
1523}
1524
1525static std::unique_ptr<BakeItem> deserialize_bake_item(const DictionaryValue &io_item,
1526 const BlobReader &blob_reader,
1527 const BlobReadSharing &blob_sharing)
1528{
1529
1530 const std::optional<StringRefNull> state_item_type = io_item.lookup_str("type");
1531 if (!state_item_type) {
1532 return {};
1533 }
1534 if (*state_item_type == StringRef("GEOMETRY")) {
1535 const DictionaryValue *io_geometry = io_item.lookup_dict("data");
1536 if (!io_geometry) {
1537 return {};
1538 }
1539 GeometrySet geometry = load_geometry(*io_geometry, blob_reader, blob_sharing);
1540 return std::make_unique<GeometryBakeItem>(std::move(geometry));
1541 }
1542 if (*state_item_type == StringRef("ATTRIBUTE")) {
1543 const DictionaryValue *io_attribute = &io_item;
1544 if (!io_attribute) {
1545 return {};
1546 }
1547 std::optional<StringRefNull> name = io_attribute->lookup_str("name");
1548 if (!name) {
1549 return {};
1550 }
1551 return std::make_unique<AttributeBakeItem>(std::move(*name));
1552 }
1553#ifdef WITH_OPENVDB
1554 if (*state_item_type == StringRef("GRID")) {
1555 const DictionaryValue &io_grid = io_item;
1556 const auto *io_vdb = io_grid.lookup_dict("vdb");
1557 if (!io_vdb) {
1558 return {};
1559 }
1560 std::optional<BlobSlice> vdb_slice = BlobSlice::deserialize(*io_vdb);
1561 if (!vdb_slice) {
1562 return {};
1563 }
1564 openvdb::GridPtrVecPtr vdb_grids;
1565 if (!blob_reader.read_as_stream(*vdb_slice, [&](std::istream &stream) {
1566 try {
1567 openvdb::io::Stream vdb_stream{stream};
1568 vdb_grids = vdb_stream.getGrids();
1569 return true;
1570 }
1571 catch (...) {
1572 return false;
1573 }
1574 }))
1575 {
1576 return {};
1577 }
1578 if (vdb_grids->size() != 1) {
1579 return {};
1580 }
1581 std::shared_ptr<openvdb::GridBase> vdb_grid = std::move((*vdb_grids)[0]);
1582 GVolumeGrid grid{std::move(vdb_grid)};
1583 return std::make_unique<VolumeGridBakeItem>(std::make_unique<GVolumeGrid>(grid));
1584 }
1585#endif
1586 if (*state_item_type == StringRef("STRING")) {
1587 const std::shared_ptr<io::serialize::Value> *io_data = io_item.lookup("data");
1588 if (!io_data) {
1589 return {};
1590 }
1591 if (io_data->get()->type() == io::serialize::eValueType::String) {
1592 const io::serialize::StringValue &io_string = *io_data->get()->as_string_value();
1593 return std::make_unique<StringBakeItem>(io_string.value());
1594 }
1595 if (const io::serialize::DictionaryValue *io_string = io_data->get()->as_dictionary_value()) {
1596 const std::optional<int64_t> size = io_string->lookup_int("size");
1597 if (!size) {
1598 return {};
1599 }
1600 std::string str;
1601 str.resize(*size);
1602 if (!read_blob_raw_bytes(blob_reader, *io_string, *size, str.data())) {
1603 return {};
1604 }
1605 return std::make_unique<StringBakeItem>(std::move(str));
1606 }
1607 }
1608 if (*state_item_type == StringRef("BUNDLE")) {
1609 const ArrayValue *io_items = io_item.lookup_array("items");
1610 if (!io_items) {
1611 return {};
1612 }
1613 auto bundle = std::make_unique<BundleBakeItem>();
1614 for (const auto &io_item_ : io_items->elements()) {
1615 const DictionaryValue *io_item = io_item_->as_dictionary_value();
1616 if (!io_item) {
1617 return {};
1618 }
1619 const ArrayValue *io_key = io_item->lookup_array("key");
1620 if (!io_key) {
1621 return {};
1622 }
1624 for (const auto &io_key_value : io_key->elements()) {
1625 const StringValue *io_key_string = io_key_value->as_string_value();
1626 if (!io_key_string) {
1627 return {};
1628 }
1629 key.append(io_key_string->value());
1630 }
1631 const std::optional<StringRefNull> socket_idname = io_item->lookup_str("socket_idname");
1632 if (!socket_idname) {
1633 return {};
1634 }
1635 const DictionaryValue *io_item_value = io_item->lookup_dict("value");
1636 std::unique_ptr<BakeItem> value = deserialize_bake_item(
1637 *io_item_value, blob_reader, blob_sharing);
1638 if (!value) {
1639 return {};
1640 }
1641 bundle->items.append(BundleBakeItem::Item{
1642 nodes::SocketInterfaceKey{std::move(key)}, *socket_idname, std::move(value)});
1643 }
1644 return bundle;
1645 }
1646 const std::shared_ptr<io::serialize::Value> *io_data = io_item.lookup("data");
1647 if (!io_data) {
1648 return {};
1649 }
1650 const std::optional<eCustomDataType> data_type = get_data_type_from_io_name(*state_item_type);
1651 if (data_type) {
1652 const CPPType &cpp_type = *custom_data_type_to_cpp_type(*data_type);
1653 BUFFER_FOR_CPP_TYPE_VALUE(cpp_type, buffer);
1654 if (!deserialize_primitive_value(**io_data, *data_type, buffer)) {
1655 return {};
1656 }
1657 BLI_SCOPED_DEFER([&]() { cpp_type.destruct(buffer); });
1658 return std::make_unique<PrimitiveBakeItem>(cpp_type, buffer);
1659 }
1660 return {};
1661}
1662
1663static constexpr int bake_file_version = 3;
1664
1665void serialize_bake(const BakeState &bake_state,
1666 BlobWriter &blob_writer,
1667 BlobWriteSharing &blob_sharing,
1668 std::ostream &r_stream)
1669{
1671 io_root.append_int("version", bake_file_version);
1672 io::serialize::DictionaryValue &io_items = *io_root.append_dict("items");
1673 for (auto item : bake_state.items_by_id.items()) {
1674 io::serialize::DictionaryValue &io_item = *io_items.append_dict(std::to_string(item.key));
1675 serialize_bake_item(*item.value, blob_writer, blob_sharing, io_item);
1676 }
1677
1679 formatter.serialize(r_stream, io_root);
1680}
1681
1682std::optional<BakeState> deserialize_bake(std::istream &stream,
1683 const BlobReader &blob_reader,
1684 const BlobReadSharing &blob_sharing)
1685{
1686 JsonFormatter formatter;
1687 std::unique_ptr<io::serialize::Value> io_root_value;
1688 try {
1689 io_root_value = formatter.deserialize(stream);
1690 }
1691 catch (...) {
1692 return std::nullopt;
1693 }
1694 if (!io_root_value) {
1695 return std::nullopt;
1696 }
1697 const io::serialize::DictionaryValue *io_root = io_root_value->as_dictionary_value();
1698 if (!io_root) {
1699 return std::nullopt;
1700 }
1701 const std::optional<int> version = io_root->lookup_int("version");
1702 if (!version.has_value() || *version != bake_file_version) {
1703 return std::nullopt;
1704 }
1705 const io::serialize::DictionaryValue *io_items = io_root->lookup_dict("items");
1706 if (!io_items) {
1707 return std::nullopt;
1708 }
1709 BakeState bake_state;
1710 for (const auto &io_item_value : io_items->elements()) {
1711 const io::serialize::DictionaryValue *io_item = io_item_value.second->as_dictionary_value();
1712 if (!io_item) {
1713 return std::nullopt;
1714 }
1715 int id;
1716 try {
1717 id = std::stoi(io_item_value.first);
1718 }
1719 catch (...) {
1720 return std::nullopt;
1721 }
1722 if (bake_state.items_by_id.contains(id)) {
1723 return std::nullopt;
1724 }
1725 std::unique_ptr<BakeItem> bake_item = deserialize_bake_item(
1726 *io_item, blob_reader, blob_sharing);
1727 if (!bake_item) {
1728 return std::nullopt;
1729 }
1730 bake_state.items_by_id.add_new(id, std::move(bake_item));
1731 }
1732 return bake_state;
1733}
1734
1735} // namespace blender::bke::bake
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name)
Low-level operations for grease pencil.
GreasePencil * BKE_grease_pencil_new_nomain()
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1500
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
General operations for point clouds.
Volume data-block.
void BKE_volume_grid_add(Volume *volume, const blender::bke::VolumeGridData &grid)
int BKE_volume_num_grids(const Volume *volume)
const blender::bke::VolumeGridData * BKE_volume_grid_get(const Volume *volume, int grid_index)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define B_ENDIAN
#define L_ENDIAN
#define ENDIAN_ORDER
void BLI_endian_switch_uint16_array(unsigned short *val, int size) ATTR_NONNULL(1)
void BLI_endian_switch_uint64_array(uint64_t *val, int size) ATTR_NONNULL(1)
void BLI_endian_switch_uint32_array(unsigned int *val, int size) ATTR_NONNULL(1)
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define BLI_SCOPED_DEFER(function_to_defer)
#define FILE_MAX
#define BLI_path_join(...)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
@ ID_MA
struct CurvesGeometry CurvesGeometry
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_PROP_COLOR
@ CD_PROP_QUATERNION
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_INT16_2D
@ CD_PROP_FLOAT4X4
Object is a sort of wrapper for general info.
struct Volume Volume
volatile int lock
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const void * element
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const
Data buffer MUST be 16 byte aligned.
void destruct(void *ptr) const
AttributeSet attributes
void append(const T &value)
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
bool is_any() const
static const CPPType & get()
bool is() const
void copy_assign_n(const void *src, void *dst, int64_t n) const
ChannelStorageType r
Definition BLI_color.hh:93
int64_t size_in_bytes() const
const CPPType & type() const
constexpr int64_t size() const
constexpr bool is_empty() const
static constexpr IndexRange from_begin_size(const int64_t begin, const int64_t size)
constexpr int64_t start() const
constexpr bool contains(int64_t value) const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
bool contains_as(const ForwardKey &key) const
Definition BLI_set.hh:314
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool startswith(StringRef prefix) const
constexpr const char * c_str() const
void append(const T &value)
const T & last(const int64_t n=0) const
Span< T > as_span() const
void append_as(ForwardValue &&...value)
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
bool contains(StringRef attribute_id) const
int domain_size(const AttrDomain domain) const
GAttributeReader get() const
Span< InstanceReference > references() const
Definition instances.cc:285
bke::AttributeAccessor attributes() const
Definition instances.cc:63
int instances_num() const
Definition instances.cc:398
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
std::optional< ImplicitSharingInfoAndData > read_shared(const io::serialize::DictionaryValue &io_data, FunctionRef< std::optional< ImplicitSharingInfoAndData >()> read_fn) const
virtual bool read_as_stream(const BlobSlice &slice, FunctionRef< bool(std::istream &)> fn) const
virtual bool read(const BlobSlice &slice, void *r_data) const =0
std::shared_ptr< io::serialize::DictionaryValue > write_implicitly_shared(const ImplicitSharingInfo *sharing_info, FunctionRef< std::shared_ptr< io::serialize::DictionaryValue >()> write_fn)
std::shared_ptr< io::serialize::DictionaryValue > write_deduplicated(BlobWriter &writer, const void *data, int64_t size_in_bytes)
virtual BlobSlice write(const void *data, int64_t size)=0
virtual BlobSlice write_as_stream(StringRef file_extension, FunctionRef< void(std::ostream &)> fn)
bool read(const BlobSlice &slice, void *r_data) const override
DiskBlobWriter(std::string blob_dir, std::string base_name)
BlobSlice write_as_stream(StringRef file_extension, FunctionRef< void(std::ostream &)> fn) override
BlobSlice write(const void *data, int64_t size) override
void add(StringRef name, Span< std::byte > blob)
bool read(const BlobSlice &slice, void *r_data) const override
BlobSlice write(const void *data, int64_t size) override
BlobSlice write_as_stream(StringRef file_extension, FunctionRef< void(std::ostream &)> fn) override
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
void set_local_transform(const float4x4 &transform)
Span< std::shared_ptr< Value > > elements() const
void append_str(std::string value)
Definition serialize.cc:232
std::shared_ptr< DictionaryValue > append_dict()
Definition serialize.cc:242
const std::shared_ptr< Value > * lookup(StringRef key) const
Definition serialize.cc:265
void append(std::string key, std::shared_ptr< Value > value)
Definition serialize.cc:321
std::optional< StringRefNull > lookup_str(StringRef key) const
Definition serialize.cc:275
void append_str(std::string key, std::string value)
Definition serialize.cc:336
std::shared_ptr< DictionaryValue > append_dict(std::string key)
Definition serialize.cc:341
std::optional< int64_t > lookup_int(StringRef key) const
Definition serialize.cc:285
void append_int(std::string key, int64_t value)
Definition serialize.cc:326
std::shared_ptr< ArrayValue > append_array(std::string key)
Definition serialize.cc:348
const DictionaryValue * lookup_dict(StringRef key) const
Definition serialize.cc:305
const ArrayValue * lookup_array(StringRef key) const
Definition serialize.cc:313
std::unique_ptr< Value > deserialize(std::istream &is) override
Definition serialize.cc:367
void serialize(std::ostream &os, const Value &value) override
Definition serialize.cc:355
const BooleanValue * as_boolean_value() const
Definition serialize.cc:40
const ArrayValue * as_array_value() const
Definition serialize.cc:56
const IntValue * as_int_value() const
Definition serialize.cc:24
const DoubleValue * as_double_value() const
Definition serialize.cc:32
const DictionaryValue * as_dictionary_value() const
Definition serialize.cc:64
std::string id_name(void *id)
#define str(s)
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define T
static bool deserialize_typed_array(const io::serialize::Value &io_value, FunctionRef< std::optional< T >(const io::serialize::Value &io_element)> fn, MutableSpan< T > r_values)
static StringRefNull get_domain_io_name(const AttrDomain domain)
static constexpr int bake_file_version
static bool read_blob_shared_simple_span(const DictionaryValue &io_data, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing, const int size, T **r_data, const ImplicitSharingInfo **r_sharing_info)
static std::optional< AttrDomain > get_domain_from_io_name(const StringRefNull io_name)
static std::optional< eCustomDataType > get_data_type_from_io_name(const StringRefNull io_name)
static bool deserialize_int_array(const io::serialize::Value &io_value, MutableSpan< T > r_values)
static bool read_blob_simple_gspan(const BlobReader &blob_reader, const DictionaryValue &io_data, GMutableSpan r_data)
static std::shared_ptr< io::serialize::ArrayValue > serialize_int_array(const Span< int > values)
std::shared_ptr< DictionaryValue > DictionaryValuePtr
Definition bake_items.cc:23
static bool read_blob_raw_bytes(const BlobReader &blob_reader, const DictionaryValue &io_data, const int64_t bytes_num, void *r_data)
static StringRefNull get_data_type_io_name(const eCustomDataType data_type)
static bool load_materials(const io::serialize::ArrayValue &io_materials, std::unique_ptr< BakeMaterialsList > &materials)
static StringRefNull get_endian_io_name(const int endian)
static std::optional< CurvesGeometry > try_load_curves_geometry(const DictionaryValue &io_curves, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static std::optional< float > deserialize_float(const io::serialize::Value &io_value)
static std::optional< T > deserialize_int(const io::serialize::Value &io_value)
static std::shared_ptr< io::serialize::Value > serialize_primitive_value(const eCustomDataType data_type, const void *value_ptr)
static bool load_attributes(const io::serialize::ArrayValue &io_attributes, MutableAttributeAccessor &attributes, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
void serialize_bake(const BakeState &bake_state, BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, std::ostream &r_stream)
static void serialize_curves_geometry(DictionaryValue &io_curves, const CurvesGeometry &curves, BlobWriter &blob_writer, BlobWriteSharing &blob_sharing)
static std::shared_ptr< DictionaryValue > write_blob_raw_bytes(BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, const void *data, const int64_t size_in_bytes)
static std::shared_ptr< DictionaryValue > serialize_geometry_set(const GeometrySet &geometry, BlobWriter &blob_writer, BlobWriteSharing &blob_sharing)
static Curves * try_load_curves(const DictionaryValue &io_geometry, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static std::shared_ptr< DictionaryValue > write_blob_shared_simple_gspan(BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, const GSpan data, const ImplicitSharingInfo *sharing_info)
static GeometrySet load_geometry(const DictionaryValue &io_geometry, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static void serialize_bake_item(const BakeItem &item, BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, DictionaryValue &r_io_item)
static Mesh * try_load_mesh(const DictionaryValue &io_geometry, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static std::unique_ptr< BakeItem > deserialize_bake_item(const DictionaryValue &io_item, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static PointCloud * try_load_pointcloud(const DictionaryValue &io_geometry, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
std::optional< BakeState > deserialize_bake(std::istream &stream, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static bool deserialize_primitive_value(const io::serialize::Value &io_value, const eCustomDataType type, void *r_value)
static std::shared_ptr< DictionaryValue > write_blob_simple_gspan(BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, const GSpan data)
static GreasePencil * try_load_grease_pencil(const DictionaryValue &io_geometry, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static const void * read_blob_shared_simple_gspan(const DictionaryValue &io_data, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing, const CPPType &cpp_type, const int size, const ImplicitSharingInfo **r_sharing_info)
static std::unique_ptr< Instances > try_load_instances(const DictionaryValue &io_geometry, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
static bool deserialize_float_array(const io::serialize::Value &io_value, MutableSpan< float > r_values)
static std::shared_ptr< DictionaryValue > write_blob_raw_data_with_endian(BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, const void *data, const int64_t size_in_bytes)
static std::string make_independent_file_name(const StringRef base_name, const int file_index, const StringRef extension)
static std::shared_ptr< io::serialize::ArrayValue > serialize_float_array(const Span< float > values)
static std::shared_ptr< io::serialize::ArrayValue > serialize_attributes(const AttributeAccessor &attributes, BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, const Set< std::string > &attributes_to_ignore)
static std::shared_ptr< io::serialize::ArrayValue > serialize_materials(const std::unique_ptr< BakeMaterialsList > &materials)
static bool read_blob_raw_data_with_endian(const BlobReader &blob_reader, const DictionaryValue &io_data, const int64_t element_size, const int64_t elements_num, void *r_data)
bool attribute_name_is_anonymous(const StringRef name)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
const CPPType * custom_data_type_to_cpp_type(eCustomDataType type)
PointCloud * pointcloud_new_no_attributes(int totpoint)
Curves * curves_new_nomain(int points_num, int curves_num)
const ImplicitSharingInfo * info_for_mem_free(void *data)
PrimitiveValue< int64_t, eValueType::Int > IntValue
PrimitiveValue< bool, eValueType::Boolean > BooleanValue
PrimitiveValue< double, eValueType::Double > DoubleValue
QuaternionBase< float > Quaternion
VecBase< int32_t, 4 > int4
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
blender::VecBase< int16_t, 2 > short2
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
Definition BLI_color.hh:343
bool RNA_enum_id_from_value(const EnumPropertyItem *item, int value, const char **r_identifier)
bool RNA_enum_value_from_identifier(const EnumPropertyItem *item, const char *identifier, int *r_value)
const EnumPropertyItem rna_enum_attribute_domain_items[]
const EnumPropertyItem rna_enum_attribute_type_items[]
CurvesGeometry geometry
GreasePencilRuntimeHandle * runtime
PointCloudRuntimeHandle * runtime
VolumeRuntimeHandle * runtime
const T * base_ptr() const
const ImplicitSharingInfo * sharing_info
Map< int, std::unique_ptr< BakeItem > > items_by_id
std::shared_ptr< io::serialize::DictionaryValue > serialize() const
static std::optional< BlobSlice > deserialize(const io::serialize::DictionaryValue &io_slice)
read
i
Definition text_draw.cc:230