Blender V4.3
abstract_hierarchy_iterator.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
6
7#include <climits>
8#include <cstdio>
9#include <iostream>
10#include <sstream>
11#include <string>
12
13#include "BKE_anim_data.hh"
14#include "BKE_duplilist.hh"
15#include "BKE_key.hh"
16#include "BKE_object.hh"
17#include "BKE_particle.h"
18
19#include "BLI_assert.h"
20#include "BLI_listbase.h"
21#include "BLI_math_matrix.h"
22
23#include "DNA_ID.h"
24#include "DNA_layer_types.h"
25#include "DNA_modifier_types.h"
26#include "DNA_object_types.h"
27#include "DNA_particle_types.h"
28#include "DNA_rigidbody_types.h"
29
31
32namespace blender::io {
33
35{
36 return nullptr;
37}
38
40{
41 if (object != other.object) {
42 return object < other.object;
43 }
44 if (duplicator != nullptr && duplicator == other.duplicator) {
45 /* Only resort to string comparisons when both objects are created by the same duplicator. */
46 return export_name < other.export_name;
47 }
48
49 return export_parent < other.export_parent;
50}
51
53{
54 return !original_export_path.empty();
55}
56void HierarchyContext::mark_as_instance_of(const std::string &reference_export_path)
57{
58 original_export_path = reference_export_path;
59}
64
65bool HierarchyContext::is_object_visible(const enum eEvaluationMode evaluation_mode) const
66{
67 const bool is_dupli = duplicator != nullptr;
68 int base_flag;
69
70 if (is_dupli) {
71 /* Construct the object's base flags from its dupli-parent, just like is done in
72 * deg_objects_dupli_iterator_next(). Without this, the visibility check below will fail. Doing
73 * this here, instead of a more suitable location in AbstractHierarchyIterator, prevents
74 * copying the Object for every dupli. */
75 base_flag = object->base_flag;
76 object->base_flag = duplicator->base_flag | BASE_FROM_DUPLI;
77 }
78
79 const int visibility = BKE_object_visibility(object, evaluation_mode);
80
81 if (is_dupli) {
82 object->base_flag = base_flag;
83 }
84
85 return (visibility & OB_VISIBLE_SELF) != 0;
86}
87
88EnsuredWriter::EnsuredWriter() : writer_(nullptr), newly_created_(false) {}
89
91 : writer_(writer), newly_created_(newly_created)
92{
93}
94
96{
97 return EnsuredWriter(nullptr, false);
98}
100{
101 return EnsuredWriter(writer, false);
102}
107
109{
110 return newly_created_;
111}
112
113EnsuredWriter::operator bool() const
114{
115 return writer_ != nullptr;
116}
117
119{
120 return writer_;
121}
122
124{
125 Object *object = context.object;
126
127 if (BKE_animdata_id_is_animated(static_cast<ID *>(object->data))) {
128 return true;
129 }
130 if (BKE_key_from_object(object) != nullptr) {
131 return true;
132 }
133 if (check_has_deforming_physics(context)) {
134 return true;
135 }
136
137 /* Test modifiers. */
138 /* TODO(Sybren): replace this with a check on the depsgraph to properly check for dependency on
139 * time. */
140 ModifierData *md = static_cast<ModifierData *>(object->modifiers.first);
141 while (md) {
142 if (md->type != eModifierType_Subsurf) {
143 return true;
144 }
145 md = md->next;
146 }
147
148 return false;
149}
150
152{
153 const RigidBodyOb *rbo = context.object->rigidbody_object;
154 return rbo != nullptr && rbo->type == RBO_TYPE_ACTIVE;
155}
156
158{
159 const RigidBodyOb *rbo = context.object->rigidbody_object;
160 return rbo != nullptr && rbo->type == RBO_TYPE_ACTIVE && (rbo->flag & RBO_FLAG_USE_DEFORM) != 0;
161}
162
164 : bmain_(bmain), depsgraph_(depsgraph), export_subset_({true, true})
165{
166}
167
169{
170 /* release_writers() cannot be called here directly, as it calls into the pure-virtual
171 * release_writer() function. By the time this destructor is called, the subclass that implements
172 * that pure-virtual function is already destructed. */
174 writers_.empty(),
175 "release_writers() should be called before the AbstractHierarchyIterator goes out of scope");
176}
177
179{
180 export_graph_construct();
181 connect_loose_objects();
182 export_graph_prune();
183 determine_export_paths(HierarchyContext::root());
184 determine_duplication_references(HierarchyContext::root(), "");
185 make_writers(HierarchyContext::root());
186 export_graph_clear();
187}
188
190{
191 for (WriterMap::value_type it : writers_) {
192 release_writer(it.second);
193 }
194 writers_.clear();
195}
196
198{
199 export_subset_ = export_subset;
200}
201
202std::string AbstractHierarchyIterator::make_valid_name(const std::string &name) const
203{
204 return name;
205}
206
207std::string AbstractHierarchyIterator::get_id_name(const ID *id) const
208{
209 if (id == nullptr) {
210 return "";
211 }
212
213 return make_valid_name(std::string(id->name + 2));
214}
215
217{
218 BLI_assert(!context->export_path.empty());
219 BLI_assert(context->object->data);
220
221 return path_concatenate(context->export_path, get_object_data_name(context->object));
222}
223
224void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &graph) const
225{
226 size_t total_graph_size = 0;
227 for (const ExportGraph::value_type &map_iter : graph) {
228 const ObjectIdentifier &parent_info = map_iter.first;
229 const Object *const export_parent = parent_info.object;
230 const Object *const duplicator = parent_info.duplicated_by;
231
232 if (duplicator != nullptr) {
233 printf(" DU %s (as dupped by %s):\n",
234 export_parent == nullptr ? "-null-" : (export_parent->id.name + 2),
235 duplicator->id.name + 2);
236 }
237 else {
238 printf(" OB %s:\n", export_parent == nullptr ? "-null-" : (export_parent->id.name + 2));
239 }
240
241 total_graph_size += map_iter.second.size();
242 for (HierarchyContext *child_ctx : map_iter.second) {
243 if (child_ctx->duplicator == nullptr) {
244 printf(" - %s%s%s\n",
245 child_ctx->export_name.c_str(),
246 child_ctx->weak_export ? " (weak)" : "",
247 child_ctx->original_export_path.empty() ?
248 "" :
249 (std::string("ref ") + child_ctx->original_export_path).c_str());
250 }
251 else {
252 printf(" - %s (dup by %s%s) %s\n",
253 child_ctx->export_name.c_str(),
254 child_ctx->duplicator->id.name + 2,
255 child_ctx->weak_export ? ", weak" : "",
256 child_ctx->original_export_path.empty() ?
257 "" :
258 (std::string("ref ") + child_ctx->original_export_path).c_str());
259 }
260 }
261 }
262 printf(" (Total graph size: %zu objects)\n", total_graph_size);
263}
264
265void AbstractHierarchyIterator::export_graph_construct()
266{
268
269 /* Add a "null" root node with no children immediately for the case where the top-most node in
270 * the scene is not being exported and a root node otherwise wouldn't get added. */
271 ExportGraph::key_type root_node_id = ObjectIdentifier::for_real_object(nullptr);
272 export_graph_[root_node_id] = ExportChildren();
273
274 DEGObjectIterSettings deg_iter_settings{};
275 deg_iter_settings.depsgraph = depsgraph_;
276 deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
278 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, object) {
279 /* Non-instanced objects always have their object-parent as export-parent. */
280 const bool weak_export = mark_as_weak_export(object);
281 visit_object(object, object->parent, weak_export);
282
283 if (weak_export) {
284 /* If a duplicator shouldn't be exported, its duplilist also shouldn't be. */
285 continue;
286 }
287
288 /* Export the duplicated objects instanced by this object. */
289 ListBase *lb = object_duplilist(depsgraph_, scene, object);
290 if (lb) {
291 DupliParentFinder dupli_parent_finder;
292
293 LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
294 PersistentID persistent_id(dupli_object);
295 if (!should_visit_dupli_object(dupli_object)) {
296 continue;
297 }
298 dupli_parent_finder.insert(dupli_object);
299 }
300
301 LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
302 if (!should_visit_dupli_object(dupli_object)) {
303 continue;
304 }
305 visit_dupli_object(dupli_object, object, dupli_parent_finder);
306 }
307 }
308
310 }
312}
313
314void AbstractHierarchyIterator::connect_loose_objects()
315{
316 /* Find those objects whose parent is not part of the export graph; these
317 * objects would be skipped when traversing the graph as a hierarchy.
318 * These objects will have to be re-attached to some parent object in order to
319 * fit into the hierarchy. */
320 ExportGraph loose_objects_graph = export_graph_;
321 for (const ExportGraph::value_type &map_iter : export_graph_) {
322 for (const HierarchyContext *child : map_iter.second) {
323 /* An object that is marked as a child of another object is not considered 'loose'. */
324 ObjectIdentifier child_oid = ObjectIdentifier::for_hierarchy_context(child);
325 loose_objects_graph.erase(child_oid);
326 }
327 }
328 /* The root of the hierarchy is always found, so it's never considered 'loose'. */
329 loose_objects_graph.erase(ObjectIdentifier::for_graph_root());
330
331 /* Iterate over the loose objects and connect them to their export parent. */
332 for (const ExportGraph::value_type &map_iter : loose_objects_graph) {
333 const ObjectIdentifier &graph_key = map_iter.first;
334 Object *object = graph_key.object;
335
336 while (true) {
337 /* Loose objects will all be real objects, as duplicated objects always have
338 * their duplicator or other exported duplicated object as ancestor. */
339
340 ExportGraph::iterator found_parent_iter = export_graph_.find(
341 ObjectIdentifier::for_real_object(object->parent));
342 visit_object(object, object->parent, true);
343 if (found_parent_iter != export_graph_.end()) {
344 break;
345 }
346 /* 'object->parent' will never be nullptr here, as the export graph contains the
347 * root as nullptr and thus will cause a break above. */
348 BLI_assert(object->parent != nullptr);
349
350 object = object->parent;
351 }
352 }
353}
354
355static bool remove_weak_subtrees(const HierarchyContext *context,
358{
359 bool all_is_weak = context != nullptr && context->weak_export;
361
362 AbstractHierarchyIterator::ExportGraph::const_iterator child_iterator;
363
364 child_iterator = input_graph.find(map_key);
365 if (child_iterator != input_graph.end()) {
366 for (HierarchyContext *child_context : child_iterator->second) {
367 bool child_tree_is_weak = remove_weak_subtrees(child_context, clean_graph, input_graph);
368 all_is_weak &= child_tree_is_weak;
369
370 if (child_tree_is_weak) {
371 /* This subtree is all weak, so we can remove it from the current object's children. */
372 clean_graph[map_key].erase(child_context);
373 delete child_context;
374 }
375 }
376 }
377
378 if (all_is_weak) {
379 /* This node and all its children are weak, so it can be removed from the export graph. */
380 clean_graph.erase(map_key);
381 }
382
383 return all_is_weak;
384}
385
386void AbstractHierarchyIterator::export_graph_prune()
387{
388 /* Take a copy of the map so that we can modify while recusing. */
389 ExportGraph unpruned_export_graph = export_graph_;
391}
392
393void AbstractHierarchyIterator::export_graph_clear()
394{
395 for (ExportGraph::iterator::value_type &it : export_graph_) {
396 for (HierarchyContext *context : it.second) {
397 delete context;
398 }
399 }
400 export_graph_.clear();
401}
402
403void AbstractHierarchyIterator::visit_object(Object *object,
404 Object *export_parent,
405 bool weak_export)
406{
407 HierarchyContext *context = new HierarchyContext();
408 context->object = object;
409 context->export_name = get_object_name(object);
410 context->export_parent = export_parent;
411 context->duplicator = nullptr;
412 context->weak_export = weak_export;
413 context->animation_check_include_parent = false;
414 context->export_path = "";
415 context->original_export_path = "";
416 context->higher_up_export_path = "";
417
418 copy_m4_m4(context->matrix_world, object->object_to_world().ptr());
419
420 ExportGraph::key_type graph_index = determine_graph_index_object(context);
421 context_update_for_graph_index(context, graph_index);
422
423 /* Store this HierarchyContext as child of the export parent. */
424 export_graph_[graph_index].insert(context);
425
426 /* Create an empty entry for this object to indicate it is part of the export. This will be used
427 * by connect_loose_objects(). Having such an "indicator" will make it possible to do an O(log n)
428 * check on whether an object is part of the export, rather than having to check all objects in
429 * the map. Note that it's not possible to simply search for (object->parent, nullptr), as the
430 * object's parent in Blender may not be the same as its export-parent. */
431 ExportGraph::key_type object_key = ObjectIdentifier::for_real_object(object);
432 if (export_graph_.find(object_key) == export_graph_.end()) {
433 export_graph_[object_key] = ExportChildren();
434 }
435}
436
437AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
439{
440 return ObjectIdentifier::for_real_object(context->export_parent);
441}
442
443void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
444 Object *duplicator,
445 const DupliParentFinder &dupli_parent_finder)
446{
447 HierarchyContext *context = new HierarchyContext();
448 context->object = dupli_object->ob;
449 context->duplicator = duplicator;
450 context->persistent_id = PersistentID(dupli_object);
451 context->weak_export = false;
452 context->export_path = "";
453 context->original_export_path = "";
454 context->animation_check_include_parent = false;
455
456 copy_m4_m4(context->matrix_world, dupli_object->mat);
457
458 /* Construct export name for the dupli-instance. */
459 std::stringstream export_name_stream;
460 export_name_stream << get_object_name(context->object) << "-"
461 << context->persistent_id.as_object_name_suffix();
462 context->export_name = make_valid_name(export_name_stream.str());
463
464 ExportGraph::key_type graph_index = determine_graph_index_dupli(
465 context, dupli_object, dupli_parent_finder);
466 context_update_for_graph_index(context, graph_index);
467
468 export_graph_[graph_index].insert(context);
469}
470
471AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
473 const DupliObject *dupli_object,
474 const DupliParentFinder &dupli_parent_finder)
475{
476 const DupliObject *dupli_parent = dupli_parent_finder.find_suitable_export_parent(dupli_object);
477
478 if (dupli_parent != nullptr) {
479 return ObjectIdentifier::for_duplicated_object(dupli_parent, context->duplicator);
480 }
481 return ObjectIdentifier::for_real_object(context->duplicator);
482}
483
484void AbstractHierarchyIterator::context_update_for_graph_index(
485 HierarchyContext *context, const ExportGraph::key_type &graph_index) const
486{
487 /* Update the HierarchyContext so that it is consistent with the graph index. */
488 context->export_parent = graph_index.object;
489
490 /* If the parent type is such that it cannot be exported (at least not currently to USD or
491 * Alembic), always check the parent for animation. */
492 const short partype = context->object->partype & PARTYPE;
493 context->animation_check_include_parent |= ELEM(partype, PARBONE, PARVERT1, PARVERT3, PARSKEL);
494
495 if (context->export_parent != context->object->parent) {
496 /* The parent object in Blender is NOT used as the export parent. This means
497 * that the world transform of this object can be influenced by objects that
498 * are not part of its export graph. */
499 context->animation_check_include_parent = true;
500 }
501}
502
508
509void AbstractHierarchyIterator::determine_export_paths(const HierarchyContext *parent_context)
510{
511 const std::string &parent_export_path = parent_context ? parent_context->export_path : "";
512
513 for (HierarchyContext *context : graph_children(parent_context)) {
514 context->export_path = path_concatenate(parent_export_path, context->export_name);
515
516 if (context->duplicator == nullptr) {
517 /* This is an original (i.e. non-instanced) object, so we should keep track of where it was
518 * exported to, just in case it gets instanced somewhere. */
519 ID *source_ob = &context->object->id;
520 duplisource_export_path_[source_ob] = context->export_path;
521
522 if (context->object->data != nullptr) {
523 ID *source_data = static_cast<ID *>(context->object->data);
525 }
526 }
527
528 determine_export_paths(context);
529 }
530}
531
532void AbstractHierarchyIterator::determine_duplication_references(
533 const HierarchyContext *parent_context, const std::string &indent)
534{
535 ExportChildren children = graph_children(parent_context);
536
537 for (HierarchyContext *context : children) {
538 if (context->duplicator != nullptr) {
539 ID *source_id = &context->object->id;
540 const ExportPathMap::const_iterator &it = duplisource_export_path_.find(source_id);
541
542 if (it == duplisource_export_path_.end()) {
543 /* The original was not found, so mark this instance as "the original". */
544 context->mark_as_not_instanced();
545 duplisource_export_path_[source_id] = context->export_path;
546 }
547 else {
548 context->mark_as_instance_of(it->second);
549 }
550
551 if (context->object->data) {
552 ID *source_data_id = (ID *)context->object->data;
553 const ExportPathMap::const_iterator &it = duplisource_export_path_.find(source_data_id);
554
555 if (it == duplisource_export_path_.end()) {
556 /* The original was not found, so mark this instance as "original". */
557 std::string data_path = get_object_data_path(context);
558 context->mark_as_not_instanced();
559 duplisource_export_path_[source_id] = context->export_path;
560 duplisource_export_path_[source_data_id] = data_path;
561 }
562 }
563 }
564
565 determine_duplication_references(context, indent + " ");
566 }
567}
568
569void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_context)
570{
571 float parent_matrix_inv_world[4][4];
572
573 if (parent_context) {
574 invert_m4_m4(parent_matrix_inv_world, parent_context->matrix_world);
575 }
576 else {
577 unit_m4(parent_matrix_inv_world);
578 }
579
580 for (HierarchyContext *context : graph_children(parent_context)) {
581 /* Update the context so that it is correct for this parent-child relation. */
582 copy_m4_m4(context->parent_matrix_inv_world, parent_matrix_inv_world);
583 if (parent_context != nullptr) {
584 context->higher_up_export_path = parent_context->export_path;
585 }
586
587 /* Get or create the transform writer. */
588 EnsuredWriter transform_writer = ensure_writer(
590
591 if (!transform_writer) {
592 /* Unable to export, so there is nothing to attach any children to; just abort this entire
593 * branch of the export hierarchy. */
594 return;
595 }
596
597 BLI_assert(DEG_is_evaluated_object(context->object));
598 if (transform_writer.is_newly_created() || export_subset_.transforms) {
599 /* XXX This can lead to too many XForms being written. For example, a camera writer can
600 * refuse to write an orthographic camera. By the time that this is known, the XForm has
601 * already been written. */
602 transform_writer->write(*context);
603 }
604
605 if (!context->weak_export) {
606 make_writers_particle_systems(context);
607 make_writer_object_data(context);
608 }
609
610 /* Recurse into this object's children. */
611 make_writers(context);
612 }
613
614 /* TODO(Sybren): iterate over all unused writers and call unused_during_iteration() or something.
615 */
616}
617
618HierarchyContext AbstractHierarchyIterator::context_for_object_data(
619 const HierarchyContext *object_context) const
620{
621 HierarchyContext data_context = *object_context;
622 data_context.higher_up_export_path = object_context->export_path;
623 data_context.export_name = get_object_data_name(data_context.object);
624 data_context.export_path = path_concatenate(data_context.higher_up_export_path,
625 data_context.export_name);
626 return data_context;
627}
628
629void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext *context)
630{
631 if (context->object->data == nullptr) {
632 return;
633 }
634
635 HierarchyContext data_context = context_for_object_data(context);
636 if (data_context.is_instance()) {
637 ID *object_data = static_cast<ID *>(context->object->data);
638 data_context.original_export_path = duplisource_export_path_[object_data];
639
640 /* If the object is marked as an instance, so should the object data. */
641 BLI_assert(data_context.is_instance());
642 }
643
644 /* Always write upon creation, otherwise depend on which subset is active. */
645 EnsuredWriter data_writer = ensure_writer(&data_context,
647 if (!data_writer) {
648 return;
649 }
650
651 if (data_writer.is_newly_created() || export_subset_.shapes) {
652 data_writer->write(data_context);
653 }
654}
655
656void AbstractHierarchyIterator::make_writers_particle_systems(
657 const HierarchyContext *transform_context)
658{
659 Object *object = transform_context->object;
660 ParticleSystem *psys = static_cast<ParticleSystem *>(object->particlesystem.first);
661 for (; psys; psys = psys->next) {
662 if (!psys_check_enabled(object, psys, true)) {
663 continue;
664 }
665
666 HierarchyContext hair_context = *transform_context;
667 hair_context.export_name = make_valid_name(psys->name);
668 hair_context.export_path = path_concatenate(transform_context->export_path,
669 hair_context.export_name);
670 hair_context.higher_up_export_path = transform_context->export_path;
671 hair_context.particle_system = psys;
672
673 EnsuredWriter writer;
674 switch (psys->part->type) {
675 case PART_HAIR:
676 writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer);
677 break;
678 case PART_EMITTER:
679 case PART_FLUID_FLIP:
680 case PART_FLUID_SPRAY:
682 case PART_FLUID_FOAM:
688 writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer);
689 break;
690 }
691 if (!writer) {
692 continue;
693 }
694
695 /* Always write upon creation, otherwise depend on which subset is active. */
696 if (writer.is_newly_created() || export_subset_.shapes) {
697 writer->write(hair_context);
698 }
699 }
700}
701
702std::string AbstractHierarchyIterator::get_object_name(const Object *object) const
703{
704 return get_id_name(&object->id);
705}
706
707std::string AbstractHierarchyIterator::get_object_data_name(const Object *object) const
708{
709 ID *object_data = static_cast<ID *>(object->data);
710 return get_id_name(object_data);
711}
712
714 const std::string &export_path) const
715{
716 WriterMap::const_iterator it = writers_.find(export_path);
717
718 if (it == writers_.end()) {
719 return nullptr;
720 }
721 return it->second;
722}
723
724EnsuredWriter AbstractHierarchyIterator::ensure_writer(
725 HierarchyContext *context, AbstractHierarchyIterator::create_writer_func create_func)
726{
727 AbstractHierarchyWriter *writer = get_writer(context->export_path);
728 if (writer != nullptr) {
729 return EnsuredWriter::existing(writer);
730 }
731
732 writer = (this->*create_func)(context);
733 if (writer == nullptr) {
734 return EnsuredWriter::empty();
735 }
736
737 writers_[context->export_path] = writer;
738 return EnsuredWriter::newly_created(writer);
739}
740
741std::string AbstractHierarchyIterator::path_concatenate(const std::string &parent_path,
742 const std::string &child_path) const
743{
744 return parent_path + "/" + child_path;
745}
746
748{
749 return false;
750}
752{
753 /* Removing dupli_object->no_draw hides things like custom bone shapes. */
754 return !dupli_object->no_draw;
755}
756
757} // namespace blender::io
bool BKE_animdata_id_is_animated(const ID *id)
Definition anim_data.cc:321
ListBase * object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
void free_object_duplilist(ListBase *lb)
Key * BKE_key_from_object(Object *ob)
Definition key.cc:1820
General operations, lookup, etc. for blender objects.
@ OB_VISIBLE_SELF
int BKE_object_visibility(const Object *ob, int dag_eval_mode)
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params)
Definition particle.cc:706
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define LISTBASE_FOREACH(type, var, list)
void unit_m4(float m[4][4])
Definition rct.c:1127
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#define ELEM(...)
eEvaluationMode
#define DEG_OBJECT_ITER_BEGIN(settings_, instance_)
#define DEG_OBJECT_ITER_END
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
bool DEG_is_evaluated_object(const Object *object)
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET
ID and Library types, which are fundamental for SDNA.
@ BASE_FROM_DUPLI
@ eModifierType_Subsurf
Object is a sort of wrapper for general info.
@ PARVERT1
@ PARSKEL
@ PARTYPE
@ PARVERT3
@ PARBONE
@ PART_FLUID_FLIP
@ PART_EMITTER
@ PART_FLUID_BUBBLE
@ PART_FLUID_SPRAYBUBBLE
@ PART_FLUID_TRACER
@ PART_FLUID_FOAM
@ PART_FLUID_SPRAYFOAMBUBBLE
@ PART_FLUID_SPRAYFOAM
@ PART_HAIR
@ PART_FLUID_SPRAY
@ PART_FLUID_FOAMBUBBLE
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
@ RBO_FLAG_USE_DEFORM
std::map< ObjectIdentifier, ExportChildren > ExportGraph
virtual ExportGraph::key_type determine_graph_index_object(const HierarchyContext *context)
virtual bool should_visit_dupli_object(const DupliObject *dupli_object) const
virtual void release_writer(AbstractHierarchyWriter *writer)=0
virtual bool mark_as_weak_export(const Object *object) const
void set_export_subset(ExportSubset export_subset)
virtual std::string get_id_name(const ID *id) const
virtual AbstractHierarchyWriter * create_particle_writer(const HierarchyContext *context)=0
ExportChildren & graph_children(const HierarchyContext *context)
virtual AbstractHierarchyWriter * create_transform_writer(const HierarchyContext *context)=0
AbstractHierarchyIterator(Main *bmain, Depsgraph *depsgraph)
virtual std::string path_concatenate(const std::string &parent_path, const std::string &child_path) const
AbstractHierarchyWriter * get_writer(const std::string &export_path) const
virtual AbstractHierarchyWriter * create_data_writer(const HierarchyContext *context)=0
virtual AbstractHierarchyWriter * create_hair_writer(const HierarchyContext *context)=0
virtual std::string make_valid_name(const std::string &name) const
virtual ExportGraph::key_type determine_graph_index_dupli(const HierarchyContext *context, const DupliObject *dupli_object, const DupliParentFinder &dupli_parent_finder)
virtual std::string get_object_data_path(const HierarchyContext *context) const
virtual bool check_is_animated(const HierarchyContext &context) const
static bool check_has_deforming_physics(const HierarchyContext &context)
static bool check_has_physics(const HierarchyContext &context)
const DupliObject * find_suitable_export_parent(const DupliObject *dupli_ob) const
static EnsuredWriter existing(AbstractHierarchyWriter *writer)
static EnsuredWriter newly_created(AbstractHierarchyWriter *writer)
AbstractHierarchyWriter * operator->()
static ObjectIdentifier for_graph_root()
static ObjectIdentifier for_duplicated_object(const DupliObject *dupli_object, Object *duplicated_by)
static ObjectIdentifier for_real_object(Object *object)
static ObjectIdentifier for_hierarchy_context(const HierarchyContext *context)
#define printf
const Depsgraph * depsgraph
GPU_SHADER_INTERFACE_INFO(depth_2d_update_iface, "").smooth(Type fragColor push_constant(Type::VEC2, "extent") .push_constant(Type source_data
static bool remove_weak_subtrees(const HierarchyContext *context, AbstractHierarchyIterator::ExportGraph &clean_graph, const AbstractHierarchyIterator::ExportGraph &input_graph)
static PyObject * create_func(PyObject *, PyObject *args)
Definition python.cpp:161
float mat[4][4]
Definition DNA_ID.h:413
struct ModifierData * next
short base_flag
ParticleSettings * part
struct ParticleSystem * next
bool is_object_visible(enum eEvaluationMode evaluation_mode) const
static const HierarchyContext * root()
bool operator<(const HierarchyContext &other) const
void mark_as_instance_of(const std::string &reference_export_path)