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