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