Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSybren A. Stüvel <sybren@blender.org>2020-05-08 17:17:08 +0300
committerSybren A. Stüvel <sybren@blender.org>2020-06-19 11:17:41 +0300
commit084c5d6c7e2cf89bb9a7a9a9d00e9ee4475e222f (patch)
tree1af3f45a37e354567aed633c91d92551122cfe32 /source/blender/io/usd
parentb1ce4ca40c03ab2562863ef8056adc3b2aff5c10 (diff)
IO: Move Abstract Hierarchy Iterator into `io/common`
The goal of the `AbstractHierarchyIterator` class (and supporting classes) was to use it in different exporters. It shouldn't be part of the USD module + namespace any more, now that it will also be used in the upcoming Alembic exporter rewrite. The source files are moved into `io/common`, which is compiled & linked into a new library `bf_io_common`. The unittests are still inside the `tests/gtests/usd` directory. They should be moved to a separate test module too, but that will be delayed until after T73268 has been resolved. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D7669
Diffstat (limited to 'source/blender/io/usd')
-rw-r--r--source/blender/io/usd/CMakeLists.txt4
-rw-r--r--source/blender/io/usd/intern/abstract_hierarchy_iterator.cc652
-rw-r--r--source/blender/io/usd/intern/abstract_hierarchy_iterator.h263
-rw-r--r--source/blender/io/usd/intern/usd_hierarchy_iterator.h6
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h5
5 files changed, 11 insertions, 919 deletions
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 732a638a255..fc4f45cdef8 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -32,6 +32,7 @@ add_definitions(-DPXR_STATIC)
set(INC
.
+ ../common
../../blenkernel
../../blenlib
../../blenloader
@@ -52,7 +53,6 @@ set(INC_SYS
)
set(SRC
- intern/abstract_hierarchy_iterator.cc
intern/usd_capi.cc
intern/usd_hierarchy_iterator.cc
intern/usd_writer_abstract.cc
@@ -64,7 +64,6 @@ set(SRC
intern/usd_writer_transform.cc
usd.h
- intern/abstract_hierarchy_iterator.h
intern/usd_exporter_context.h
intern/usd_hierarchy_iterator.h
intern/usd_writer_abstract.h
@@ -79,6 +78,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_io_common
)
list(APPEND LIB
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
deleted file mode 100644
index ab83ea2c3c4..00000000000
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2019 Blender Foundation.
- * All rights reserved.
- */
-#include "abstract_hierarchy_iterator.h"
-
-#include <iostream>
-#include <limits.h>
-#include <sstream>
-#include <stdio.h>
-#include <string>
-
-#include "BKE_anim_data.h"
-#include "BKE_duplilist.h"
-#include "BKE_key.h"
-#include "BKE_particle.h"
-
-#include "BLI_assert.h"
-#include "BLI_listbase.h"
-#include "BLI_math_matrix.h"
-
-#include "DNA_ID.h"
-#include "DNA_layer_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-
-#include "DEG_depsgraph_query.h"
-
-namespace USD {
-
-const HierarchyContext *HierarchyContext::root()
-{
- return nullptr;
-}
-
-bool HierarchyContext::operator<(const HierarchyContext &other) const
-{
- if (object != other.object) {
- return object < other.object;
- }
- if (duplicator != nullptr && duplicator == other.duplicator) {
- // Only resort to string comparisons when both objects are created by the same duplicator.
- return export_name < other.export_name;
- }
-
- return export_parent < other.export_parent;
-}
-
-bool HierarchyContext::is_instance() const
-{
- return !original_export_path.empty();
-}
-void HierarchyContext::mark_as_instance_of(const std::string &reference_export_path)
-{
- original_export_path = reference_export_path;
-}
-void HierarchyContext::mark_as_not_instanced()
-{
- original_export_path.clear();
-}
-
-AbstractHierarchyWriter::~AbstractHierarchyWriter()
-{
-}
-
-bool AbstractHierarchyWriter::check_is_animated(const HierarchyContext &context) const
-{
- const Object *object = context.object;
-
- if (BKE_animdata_id_is_animated(static_cast<ID *>(object->data))) {
- return true;
- }
- if (BKE_key_from_object(object) != nullptr) {
- return true;
- }
-
- /* Test modifiers. */
- /* TODO(Sybren): replace this with a check on the depsgraph to properly check for dependency on
- * time. */
- ModifierData *md = static_cast<ModifierData *>(object->modifiers.first);
- while (md) {
- if (md->type != eModifierType_Subsurf) {
- return true;
- }
- md = md->next;
- }
-
- return false;
-}
-
-AbstractHierarchyIterator::AbstractHierarchyIterator(Depsgraph *depsgraph)
- : depsgraph_(depsgraph), writers_()
-{
-}
-
-AbstractHierarchyIterator::~AbstractHierarchyIterator()
-{
-}
-
-void AbstractHierarchyIterator::iterate_and_write()
-{
- export_graph_construct();
- connect_loose_objects();
- export_graph_prune();
- determine_export_paths(HierarchyContext::root());
- determine_duplication_references(HierarchyContext::root(), "");
- make_writers(HierarchyContext::root());
- export_graph_clear();
-}
-
-void AbstractHierarchyIterator::release_writers()
-{
- for (WriterMap::value_type it : writers_) {
- delete_object_writer(it.second);
- }
- writers_.clear();
-}
-
-std::string AbstractHierarchyIterator::make_valid_name(const std::string &name) const
-{
- return name;
-}
-
-std::string AbstractHierarchyIterator::get_id_name(const ID *id) const
-{
- if (id == nullptr) {
- return "";
- }
-
- return make_valid_name(std::string(id->name + 2));
-}
-
-std::string AbstractHierarchyIterator::get_object_data_path(const HierarchyContext *context) const
-{
- BLI_assert(!context->export_path.empty());
- BLI_assert(context->object->data);
-
- return path_concatenate(context->export_path, get_object_data_name(context->object));
-}
-
-void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &graph) const
-{
- size_t total_graph_size = 0;
- for (const ExportGraph::value_type &map_iter : graph) {
- const DupliAndDuplicator &parent_info = map_iter.first;
- Object *const export_parent = parent_info.first;
- Object *const duplicator = parent_info.second;
-
- if (duplicator != nullptr) {
- printf(" DU %s (as dupped by %s):\n",
- export_parent == nullptr ? "-null-" : (export_parent->id.name + 2),
- duplicator->id.name + 2);
- }
- else {
- printf(" OB %s:\n", export_parent == nullptr ? "-null-" : (export_parent->id.name + 2));
- }
-
- total_graph_size += map_iter.second.size();
- for (HierarchyContext *child_ctx : map_iter.second) {
- if (child_ctx->duplicator == nullptr) {
- printf(" - %s%s%s\n",
- child_ctx->object->id.name + 2,
- child_ctx->weak_export ? " (weak)" : "",
- child_ctx->original_export_path.size() ?
- (std::string("ref ") + child_ctx->original_export_path).c_str() :
- "");
- }
- else {
- printf(" - %s (dup by %s%s) %s\n",
- child_ctx->object->id.name + 2,
- child_ctx->duplicator->id.name + 2,
- child_ctx->weak_export ? ", weak" : "",
- child_ctx->original_export_path.size() ?
- (std::string("ref ") + child_ctx->original_export_path).c_str() :
- "");
- }
- }
- }
- printf(" (Total graph size: %zu objects\n", total_graph_size);
-}
-
-void AbstractHierarchyIterator::export_graph_construct()
-{
- Scene *scene = DEG_get_evaluated_scene(depsgraph_);
-
- DEG_OBJECT_ITER_BEGIN (depsgraph_,
- object,
- DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
- DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) {
- // Non-instanced objects always have their object-parent as export-parent.
- const bool weak_export = mark_as_weak_export(object);
- visit_object(object, object->parent, weak_export);
-
- if (weak_export) {
- // If a duplicator shouldn't be exported, its duplilist also shouldn't be.
- continue;
- }
-
- // Export the duplicated objects instanced by this object.
- ListBase *lb = object_duplilist(depsgraph_, scene, object);
- if (lb) {
- // Construct the set of duplicated objects, so that later we can determine whether a parent
- // is also duplicated itself.
- std::set<Object *> dupli_set;
- LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
- if (!should_visit_dupli_object(dupli_object)) {
- continue;
- }
- dupli_set.insert(dupli_object->ob);
- }
-
- LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
- if (!should_visit_dupli_object(dupli_object)) {
- continue;
- }
-
- visit_dupli_object(dupli_object, object, dupli_set);
- }
- }
-
- free_object_duplilist(lb);
- }
- DEG_OBJECT_ITER_END;
-}
-
-void AbstractHierarchyIterator::connect_loose_objects()
-{
- // Find those objects whose parent is not part of the export graph; these
- // objects would be skipped when traversing the graph as a hierarchy.
- // These objects will have to be re-attached to some parent object in order to
- // fit into the hierarchy.
- ExportGraph loose_objects_graph = export_graph_;
- for (const ExportGraph::value_type &map_iter : export_graph_) {
- for (const HierarchyContext *child : map_iter.second) {
- // An object that is marked as a child of another object is not considered 'loose'.
- loose_objects_graph.erase(std::make_pair(child->object, child->duplicator));
- }
- }
- // The root of the hierarchy is always found, so it's never considered 'loose'.
- loose_objects_graph.erase(std::make_pair(nullptr, nullptr));
-
- // Iterate over the loose objects and connect them to their export parent.
- for (const ExportGraph::value_type &map_iter : loose_objects_graph) {
- const DupliAndDuplicator &export_info = map_iter.first;
- Object *object = export_info.first;
-
- while (true) {
- // Loose objects will all be real objects, as duplicated objects always have
- // their duplicator or other exported duplicated object as ancestor.
-
- ExportGraph::iterator found_parent_iter = export_graph_.find(
- std::make_pair(object->parent, nullptr));
- visit_object(object, object->parent, true);
- if (found_parent_iter != export_graph_.end()) {
- break;
- }
- // 'object->parent' will never be nullptr here, as the export graph contains the
- // tuple <nullptr, nullptr> as root and thus will cause a break.
- BLI_assert(object->parent != nullptr);
-
- object = object->parent;
- }
- }
-}
-
-static bool remove_weak_subtrees(const HierarchyContext *context,
- AbstractHierarchyIterator::ExportGraph &clean_graph,
- const AbstractHierarchyIterator::ExportGraph &input_graph)
-{
- bool all_is_weak = context != nullptr && context->weak_export;
- Object *object = context != nullptr ? context->object : nullptr;
- Object *duplicator = context != nullptr ? context->duplicator : nullptr;
-
- const AbstractHierarchyIterator::DupliAndDuplicator map_key = std::make_pair(object, duplicator);
- AbstractHierarchyIterator::ExportGraph::const_iterator child_iterator;
-
- child_iterator = input_graph.find(map_key);
- if (child_iterator != input_graph.end()) {
- for (HierarchyContext *child_context : child_iterator->second) {
- bool child_tree_is_weak = remove_weak_subtrees(child_context, clean_graph, input_graph);
- all_is_weak &= child_tree_is_weak;
-
- if (child_tree_is_weak) {
- // This subtree is all weak, so we can remove it from the current object's children.
- clean_graph[map_key].erase(child_context);
- delete child_context;
- }
- }
- }
-
- if (all_is_weak) {
- // This node and all its children are weak, so it can be removed from the export graph.
- clean_graph.erase(map_key);
- }
-
- return all_is_weak;
-}
-
-void AbstractHierarchyIterator::export_graph_prune()
-{
- // Take a copy of the map so that we can modify while recursing.
- ExportGraph unpruned_export_graph = export_graph_;
- remove_weak_subtrees(HierarchyContext::root(), export_graph_, unpruned_export_graph);
-}
-
-void AbstractHierarchyIterator::export_graph_clear()
-{
- for (ExportGraph::iterator::value_type &it : export_graph_) {
- for (HierarchyContext *context : it.second) {
- delete context;
- }
- }
- export_graph_.clear();
-}
-
-void AbstractHierarchyIterator::visit_object(Object *object,
- Object *export_parent,
- bool weak_export)
-{
- HierarchyContext *context = new HierarchyContext();
- context->object = object;
- context->export_name = get_object_name(object);
- context->export_parent = export_parent;
- context->duplicator = nullptr;
- context->weak_export = weak_export;
- context->animation_check_include_parent = false;
- context->export_path = "";
- context->original_export_path = "";
- copy_m4_m4(context->matrix_world, object->obmat);
-
- ExportGraph::key_type graph_index = determine_graph_index_object(context);
- context_update_for_graph_index(context, graph_index);
-
- // Store this HierarchyContext as child of the export parent.
- export_graph_[graph_index].insert(context);
-
- // Create an empty entry for this object to indicate it is part of the export. This will be used
- // by connect_loose_objects(). Having such an "indicator" will make it possible to do an O(log n)
- // check on whether an object is part of the export, rather than having to check all objects in
- // the map. Note that it's not possible to simply search for (object->parent, nullptr), as the
- // object's parent in Blender may not be the same as its export-parent.
- ExportGraph::key_type object_key = std::make_pair(object, nullptr);
- if (export_graph_.find(object_key) == export_graph_.end()) {
- export_graph_[object_key] = ExportChildren();
- }
-}
-
-AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
- determine_graph_index_object(const HierarchyContext *context)
-{
- return std::make_pair(context->export_parent, nullptr);
-}
-
-void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
- Object *duplicator,
- const std::set<Object *> &dupli_set)
-{
- HierarchyContext *context = new HierarchyContext();
- context->object = dupli_object->ob;
- context->duplicator = duplicator;
- context->weak_export = false;
- context->export_path = "";
- context->original_export_path = "";
- context->export_path = "";
- context->animation_check_include_parent = false;
-
- copy_m4_m4(context->matrix_world, dupli_object->mat);
-
- // Construct export name for the dupli-instance.
- std::stringstream suffix_stream;
- suffix_stream << std::hex;
- for (int i = 0; i < MAX_DUPLI_RECUR && dupli_object->persistent_id[i] != INT_MAX; i++) {
- suffix_stream << "-" << dupli_object->persistent_id[i];
- }
- context->export_name = make_valid_name(get_object_name(context->object) + suffix_stream.str());
-
- ExportGraph::key_type graph_index = determine_graph_index_dupli(context, dupli_set);
- context_update_for_graph_index(context, graph_index);
- export_graph_[graph_index].insert(context);
-}
-
-AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
- determine_graph_index_dupli(const HierarchyContext *context,
- const std::set<Object *> &dupli_set)
-{
- /* If the dupli-object's parent is also instanced by this object, use that as the
- * export parent. Otherwise use the dupli-parent as export parent. */
-
- Object *parent = context->object->parent;
- if (parent != nullptr && dupli_set.find(parent) != dupli_set.end()) {
- // The parent object is part of the duplicated collection.
- return std::make_pair(parent, context->duplicator);
- }
- return std::make_pair(context->duplicator, nullptr);
-}
-
-void AbstractHierarchyIterator::context_update_for_graph_index(
- HierarchyContext *context, const ExportGraph::key_type &graph_index) const
-{
- // Update the HierarchyContext so that it is consistent with the graph index.
- context->export_parent = graph_index.first;
- if (context->export_parent != context->object->parent) {
- /* The parent object in Blender is NOT used as the export parent. This means
- * that the world transform of this object can be influenced by objects that
- * are not part of its export graph. */
- context->animation_check_include_parent = true;
- }
-}
-
-AbstractHierarchyIterator::ExportChildren &AbstractHierarchyIterator::graph_children(
- const HierarchyContext *context)
-{
- if (context == nullptr) {
- return export_graph_[std::make_pair(nullptr, nullptr)];
- }
-
- return export_graph_[std::make_pair(context->object, context->duplicator)];
-}
-
-void AbstractHierarchyIterator::determine_export_paths(const HierarchyContext *parent_context)
-{
- const std::string &parent_export_path = parent_context ? parent_context->export_path : "";
-
- for (HierarchyContext *context : graph_children(parent_context)) {
- context->export_path = path_concatenate(parent_export_path, context->export_name);
-
- if (context->duplicator == nullptr) {
- /* This is an original (i.e. non-instanced) object, so we should keep track of where it was
- * exported to, just in case it gets instanced somewhere. */
- ID *source_ob = &context->object->id;
- duplisource_export_path_[source_ob] = context->export_path;
-
- if (context->object->data != nullptr) {
- ID *source_data = static_cast<ID *>(context->object->data);
- duplisource_export_path_[source_data] = get_object_data_path(context);
- }
- }
-
- determine_export_paths(context);
- }
-}
-
-void AbstractHierarchyIterator::determine_duplication_references(
- const HierarchyContext *parent_context, std::string indent)
-{
- ExportChildren children = graph_children(parent_context);
-
- for (HierarchyContext *context : children) {
- if (context->duplicator != nullptr) {
- ID *source_id = &context->object->id;
- const ExportPathMap::const_iterator &it = duplisource_export_path_.find(source_id);
-
- if (it == duplisource_export_path_.end()) {
- // The original was not found, so mark this instance as "the original".
- context->mark_as_not_instanced();
- duplisource_export_path_[source_id] = context->export_path;
- }
- else {
- context->mark_as_instance_of(it->second);
- }
-
- if (context->object->data) {
- ID *source_data_id = (ID *)context->object->data;
- const ExportPathMap::const_iterator &it = duplisource_export_path_.find(source_data_id);
-
- if (it == duplisource_export_path_.end()) {
- // The original was not found, so mark this instance as "original".
- std::string data_path = get_object_data_path(context);
- context->mark_as_not_instanced();
- duplisource_export_path_[source_id] = context->export_path;
- duplisource_export_path_[source_data_id] = data_path;
- }
- }
- }
-
- determine_duplication_references(context, indent + " ");
- }
-}
-
-void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_context)
-{
- AbstractHierarchyWriter *transform_writer = nullptr;
- float parent_matrix_inv_world[4][4];
-
- if (parent_context) {
- invert_m4_m4(parent_matrix_inv_world, parent_context->matrix_world);
- }
- else {
- unit_m4(parent_matrix_inv_world);
- }
-
- for (HierarchyContext *context : graph_children(parent_context)) {
- // Update the context so that it is correct for this parent-child relation.
- copy_m4_m4(context->parent_matrix_inv_world, parent_matrix_inv_world);
-
- // Get or create the transform writer.
- transform_writer = ensure_writer(context, &AbstractHierarchyIterator::create_transform_writer);
- if (transform_writer == nullptr) {
- // Unable to export, so there is nothing to attach any children to; just abort this entire
- // branch of the export hierarchy.
- return;
- }
-
- BLI_assert(DEG_is_evaluated_object(context->object));
- /* XXX This can lead to too many XForms being written. For example, a camera writer can refuse
- * to write an orthographic camera. By the time that this is known, the XForm has already been
- * written. */
- transform_writer->write(*context);
-
- if (!context->weak_export) {
- make_writers_particle_systems(context);
- make_writer_object_data(context);
- }
-
- // Recurse into this object's children.
- make_writers(context);
- }
-
- // TODO(Sybren): iterate over all unused writers and call unused_during_iteration() or something.
-}
-
-void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext *context)
-{
- if (context->object->data == nullptr) {
- return;
- }
-
- HierarchyContext data_context = *context;
- data_context.export_path = get_object_data_path(context);
-
- /* data_context.original_export_path is just a copy from the context. It points to the object,
- * but needs to point to the object data. */
- if (data_context.is_instance()) {
- ID *object_data = static_cast<ID *>(context->object->data);
- data_context.original_export_path = duplisource_export_path_[object_data];
-
- /* If the object is marked as an instance, so should the object data. */
- BLI_assert(data_context.is_instance());
- }
-
- AbstractHierarchyWriter *data_writer;
- data_writer = ensure_writer(&data_context, &AbstractHierarchyIterator::create_data_writer);
- if (data_writer == nullptr) {
- return;
- }
-
- data_writer->write(data_context);
-}
-
-void AbstractHierarchyIterator::make_writers_particle_systems(
- const HierarchyContext *transform_context)
-{
- Object *object = transform_context->object;
- ParticleSystem *psys = static_cast<ParticleSystem *>(object->particlesystem.first);
- for (; psys; psys = psys->next) {
- if (!psys_check_enabled(object, psys, true)) {
- continue;
- }
-
- HierarchyContext hair_context = *transform_context;
- hair_context.export_path = path_concatenate(transform_context->export_path,
- make_valid_name(psys->name));
- hair_context.particle_system = psys;
-
- AbstractHierarchyWriter *writer = nullptr;
- switch (psys->part->type) {
- case PART_HAIR:
- writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer);
- break;
- case PART_EMITTER:
- writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer);
- break;
- }
-
- if (writer != nullptr) {
- writer->write(hair_context);
- }
- }
-}
-
-std::string AbstractHierarchyIterator::get_object_name(const Object *object) const
-{
- return get_id_name(&object->id);
-}
-
-std::string AbstractHierarchyIterator::get_object_data_name(const Object *object) const
-{
- ID *object_data = static_cast<ID *>(object->data);
- return get_id_name(object_data);
-}
-
-AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer(
- const std::string &export_path) const
-{
- WriterMap::const_iterator it = writers_.find(export_path);
-
- if (it == writers_.end()) {
- return nullptr;
- }
- return it->second;
-}
-
-AbstractHierarchyWriter *AbstractHierarchyIterator::ensure_writer(
- HierarchyContext *context, AbstractHierarchyIterator::create_writer_func create_func)
-{
- AbstractHierarchyWriter *writer = get_writer(context->export_path);
- if (writer != nullptr) {
- return writer;
- }
-
- writer = (this->*create_func)(context);
- if (writer == nullptr) {
- return nullptr;
- }
-
- writers_[context->export_path] = writer;
-
- return writer;
-}
-
-std::string AbstractHierarchyIterator::path_concatenate(const std::string &parent_path,
- const std::string &child_path) const
-{
- return parent_path + "/" + child_path;
-}
-
-bool AbstractHierarchyIterator::mark_as_weak_export(const Object * /*object*/) const
-{
- return false;
-}
-bool AbstractHierarchyIterator::should_visit_dupli_object(const DupliObject *dupli_object) const
-{
- // Removing dupli_object->no_draw hides things like custom bone shapes.
- return !dupli_object->no_draw;
-}
-
-} // namespace USD
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
deleted file mode 100644
index e31d5c91252..00000000000
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2019 Blender Foundation.
- * All rights reserved.
- */
-
-/*
- * This file contains the AbstractHierarchyIterator. It is intended for exporters for file
- * formats that concern an entire hierarchy of objects (rather than, for example, an OBJ file that
- * contains only a single mesh). Examples are Universal Scene Description (USD) and Alembic.
- * AbstractHierarchyIterator is intended to be subclassed to support concrete file formats.
- *
- * The AbstractHierarchyIterator makes a distinction between the actual object hierarchy and the
- * export hierarchy. The former is the parent/child structure in Blender, which can have multiple
- * parent-like objects. For example, a duplicated object can have both a duplicator and a parent,
- * both determining the final transform. The export hierarchy is the hierarchy as written to the
- * file, and every object has only one export-parent.
- *
- * Currently the AbstractHierarchyIterator does not make any decisions about *what* to export.
- * Selections like "selected only" or "no hair systems" are left to concrete subclasses.
- */
-
-#ifndef __ABSTRACT_HIERARCHY_ITERATOR_H__
-#define __ABSTRACT_HIERARCHY_ITERATOR_H__
-
-#include <map>
-#include <set>
-#include <string>
-
-struct Base;
-struct Depsgraph;
-struct DupliObject;
-struct ID;
-struct Object;
-struct ParticleSystem;
-struct ViewLayer;
-
-namespace USD {
-
-class AbstractHierarchyWriter;
-
-/* HierarchyContext structs are created by the AbstractHierarchyIterator. Each HierarchyContext
- * struct contains everything necessary to export a single object to a file. */
-struct HierarchyContext {
- /*********** Determined during hierarchy iteration: ***************/
- Object *object; /* Evaluated object. */
- Object *export_parent;
- Object *duplicator;
- float matrix_world[4][4];
- std::string export_name;
-
- /* When weak_export=true, the object will be exported only as transform, and only if is an
- * ancestor of an object with weak_export=false.
- *
- * In other words: when weak_export=true but this object has no children, or all descendants also
- * have weak_export=true, this object (and by recursive reasoning all its descendants) will be
- * excluded from the export.
- *
- * The export hierarchy is kept as close to the hierarchy in Blender as possible. As such, an
- * object that serves as a parent for another object, but which should NOT be exported itself, is
- * exported only as transform (i.e. as empty). This happens with objects that are part of a
- * holdout collection (which prevents them from being exported) but also parent of an exported
- * object. */
- bool weak_export;
-
- /* When true, this object should check its parents for animation data when determining whether
- * it's animated. This is necessary when a parent object in Blender is not part of the export. */
- bool animation_check_include_parent;
-
- /*********** Determined during writer creation: ***************/
- float parent_matrix_inv_world[4][4]; // Inverse of the parent's world matrix.
- std::string export_path; // Hierarchical path, such as "/grandparent/parent/objectname".
- ParticleSystem *particle_system; // Only set for particle/hair writers.
-
- /* Hierarchical path of the object this object is duplicating; only set when this object should
- * be stored as a reference to its original. It can happen that the original is not part of the
- * exported objects, in which case this string is empty even though 'duplicator' is set. */
- std::string original_export_path;
-
- bool operator<(const HierarchyContext &other) const;
-
- /* Return a HierarchyContext representing the root of the export hierarchy. */
- static const HierarchyContext *root();
-
- /* For handling instanced collections, instances created by particles, etc. */
- bool is_instance() const;
- void mark_as_instance_of(const std::string &reference_export_path);
- void mark_as_not_instanced();
-};
-
-/* Abstract writer for objects. Create concrete subclasses to write to USD, Alembic, etc.
- *
- * Instantiated by the AbstractHierarchyIterator on the first frame an object exists. Generally
- * that's the first frame to be exported, but can be later, for example when objects are
- * instantiated by particles. The AbstractHierarchyWriter::write() function is called on every
- * frame the object exists in the dependency graph and should be exported.
- */
-class AbstractHierarchyWriter {
- public:
- virtual ~AbstractHierarchyWriter();
- virtual void write(HierarchyContext &context) = 0;
- // TODO(Sybren): add function like absent() that's called when a writer was previously created,
- // but wasn't used while exporting the current frame (for example, a particle-instanced mesh of
- // which the particle is no longer alive).
- protected:
- virtual bool check_is_animated(const HierarchyContext &context) const;
-};
-
-/* AbstractHierarchyIterator iterates over objects in a dependency graph, and constructs export
- * writers. These writers are then called to perform the actual writing to a USD or Alembic file.
- *
- * Dealing with file- and scene-level data (for example, creating a USD scene, setting the frame
- * rate, etc.) is not part of the AbstractHierarchyIterator class structure, and should be done
- * in separate code.
- */
-class AbstractHierarchyIterator {
- public:
- /* Mapping from export path to writer. */
- typedef std::map<std::string, AbstractHierarchyWriter *> WriterMap;
- /* Pair of a (potentially duplicated) object and its duplicator (or nullptr).
- * This is typically used to store a pair of HierarchyContext::object and
- * HierarchyContext::duplicator. */
- typedef std::pair<Object *, Object *> DupliAndDuplicator;
- /* All the children of some object, as per the export hierarchy. */
- typedef std::set<HierarchyContext *> ExportChildren;
- /* Mapping from an object and its duplicator to the object's export-children. */
- typedef std::map<DupliAndDuplicator, ExportChildren> ExportGraph;
- /* Mapping from ID to its export path. This is used for instancing; given an
- * instanced datablock, the export path of the original can be looked up. */
- typedef std::map<ID *, std::string> ExportPathMap;
-
- protected:
- ExportGraph export_graph_;
- ExportPathMap duplisource_export_path_;
- Depsgraph *depsgraph_;
- WriterMap writers_;
-
- public:
- explicit AbstractHierarchyIterator(Depsgraph *depsgraph);
- virtual ~AbstractHierarchyIterator();
-
- /* Iterate over the depsgraph, create writers, and tell the writers to write.
- * Main entry point for the AbstractHierarchyIterator, must be called for every to-be-exported
- * frame. */
- void iterate_and_write();
-
- /* Release all writers. Call after all frames have been exported. */
- void release_writers();
-
- /* Convert the given name to something that is valid for the exported file format.
- * This base implementation is a no-op; override in a concrete subclass. */
- virtual std::string make_valid_name(const std::string &name) const;
-
- /* Return the name of this ID datablock that is valid for the exported file format. Overriding is
- * only necessary if make_valid_name(id->name+2) is not suitable for the exported file format.
- * NULL-safe: when `id == nullptr` this returns an empty string. */
- virtual std::string get_id_name(const ID *id) const;
-
- /* Given a HierarchyContext of some Object *, return an export path that is valid for its
- * object->data. Overriding is necessary when the exported format does NOT expect the object's
- * data to be a child of the object. */
- virtual std::string get_object_data_path(const HierarchyContext *context) const;
-
- private:
- void debug_print_export_graph(const ExportGraph &graph) const;
-
- void export_graph_construct();
- void connect_loose_objects();
- void export_graph_prune();
- void export_graph_clear();
-
- void visit_object(Object *object, Object *export_parent, bool weak_export);
- void visit_dupli_object(DupliObject *dupli_object,
- Object *duplicator,
- const std::set<Object *> &dupli_set);
-
- ExportChildren &graph_children(const HierarchyContext *parent_context);
- void context_update_for_graph_index(HierarchyContext *context,
- const ExportGraph::key_type &graph_index) const;
-
- void determine_export_paths(const HierarchyContext *parent_context);
- void determine_duplication_references(const HierarchyContext *parent_context,
- std::string indent);
-
- /* These three functions create writers and call their write() method. */
- void make_writers(const HierarchyContext *parent_context);
- void make_writer_object_data(const HierarchyContext *context);
- void make_writers_particle_systems(const HierarchyContext *context);
-
- /* Convenience wrappers around get_id_name(). */
- std::string get_object_name(const Object *object) const;
- std::string get_object_data_name(const Object *object) const;
-
- AbstractHierarchyWriter *get_writer(const std::string &export_path) const;
-
- typedef AbstractHierarchyWriter *(AbstractHierarchyIterator::*create_writer_func)(
- const HierarchyContext *);
- /* Ensure that a writer exists; if it doesn't, call create_func(context). The create_func
- * function should be one of the create_XXXX_writer(context) functions declared below. */
- AbstractHierarchyWriter *ensure_writer(HierarchyContext *context,
- create_writer_func create_func);
-
- protected:
- /* Construct a valid path for the export file format. This class concatenates by using '/' as a
- * path separator, which is valid for both Alembic and USD. */
- virtual std::string path_concatenate(const std::string &parent_path,
- const std::string &child_path) const;
-
- /* Return whether this object should be marked as 'weak export' or not.
- *
- * When this returns false, writers for the transform and data are created,
- * and dupli-objects dupli-object generated from this object will be passed to
- * should_visit_dupli_object().
- *
- * When this returns true, only a transform writer is created and marked as
- * 'weak export'. In this case, the transform writer will be removed before
- * exporting starts, unless a descendant of this object is to be exported.
- * Dupli-object generated from this object will also be skipped.
- *
- * See HierarchyContext::weak_export.
- */
- virtual bool mark_as_weak_export(const Object *object) const;
-
- virtual bool should_visit_dupli_object(const DupliObject *dupli_object) const;
-
- virtual ExportGraph::key_type determine_graph_index_object(const HierarchyContext *context);
- virtual ExportGraph::key_type determine_graph_index_dupli(const HierarchyContext *context,
- const std::set<Object *> &dupli_set);
-
- /* These functions should create an AbstractHierarchyWriter subclass instance, or return
- * nullptr if the object or its data should not be exported. Returning a nullptr for
- * data/hair/particle will NOT prevent the transform to be written.
- *
- * The returned writer is owned by the AbstractHierarchyWriter, and should be freed in
- * delete_object_writer().
- *
- * The created AbstractHierarchyWriter instances should NOT keep a copy of the context pointer.
- * The context can be stack-allocated and go out of scope. */
- virtual AbstractHierarchyWriter *create_transform_writer(const HierarchyContext *context) = 0;
- virtual AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) = 0;
- virtual AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) = 0;
- virtual AbstractHierarchyWriter *create_particle_writer(const HierarchyContext *context) = 0;
-
- /* Called by release_writers() to free what the create_XXX_writer() functions allocated. */
- virtual void delete_object_writer(AbstractHierarchyWriter *writer) = 0;
-};
-
-} // namespace USD
-
-#endif /* __ABSTRACT_HIERARCHY_ITERATOR_H__ */
diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.h b/source/blender/io/usd/intern/usd_hierarchy_iterator.h
index a608012a390..c61a0d2bf07 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.h
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.h
@@ -19,7 +19,7 @@
#ifndef __USD_HIERARCHY_ITERATOR_H__
#define __USD_HIERARCHY_ITERATOR_H__
-#include "abstract_hierarchy_iterator.h"
+#include "IO_abstract_hierarchy_iterator.h"
#include "usd.h"
#include "usd_exporter_context.h"
@@ -34,6 +34,10 @@ struct Object;
namespace USD {
+using blender::io::AbstractHierarchyIterator;
+using blender::io::AbstractHierarchyWriter;
+using blender::io::HierarchyContext;
+
class USDHierarchyIterator : public AbstractHierarchyIterator {
private:
const pxr::UsdStageRefPtr stage_;
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index 01b53f4c916..03c4c263e32 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -19,7 +19,7 @@
#ifndef __USD_WRITER_ABSTRACT_H__
#define __USD_WRITER_ABSTRACT_H__
-#include "abstract_hierarchy_iterator.h"
+#include "IO_abstract_hierarchy_iterator.h"
#include "usd_exporter_context.h"
#include <pxr/usd/sdf/path.h>
@@ -38,6 +38,9 @@ struct Object;
namespace USD {
+using blender::io::AbstractHierarchyWriter;
+using blender::io::HierarchyContext;
+
class USDAbstractWriter : public AbstractHierarchyWriter {
protected:
const USDExporterContext usd_export_context_;