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:
Diffstat (limited to 'source/blender/io/alembic/exporter')
-rw-r--r--source/blender/io/alembic/exporter/abc_custom_props.cc268
-rw-r--r--source/blender/io/alembic/exporter/abc_custom_props.h96
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_abstract.cc41
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_abstract.h41
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_camera.cc5
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_camera.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_curves.cc5
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_curves.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.cc5
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_instance.cc10
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_instance.h2
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc8
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_nurbs.cc11
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_nurbs.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_points.cc5
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_points.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_transform.cc11
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_transform.h4
20 files changed, 518 insertions, 0 deletions
diff --git a/source/blender/io/alembic/exporter/abc_custom_props.cc b/source/blender/io/alembic/exporter/abc_custom_props.cc
new file mode 100644
index 00000000000..382afdc294d
--- /dev/null
+++ b/source/blender/io/alembic/exporter/abc_custom_props.cc
@@ -0,0 +1,268 @@
+/*
+ * 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) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup Alembic
+ */
+
+#include "abc_custom_props.h"
+
+#include "abc_writer_abstract.h"
+
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <Alembic/Abc/OTypedArrayProperty.h>
+#include <Alembic/Abc/OTypedScalarProperty.h>
+
+#include "BKE_idprop.h"
+#include "DNA_ID.h"
+
+using Alembic::Abc::ArraySample;
+using Alembic::Abc::OArrayProperty;
+using Alembic::Abc::OBoolArrayProperty;
+using Alembic::Abc::OCompoundProperty;
+using Alembic::Abc::ODoubleArrayProperty;
+using Alembic::Abc::OFloatArrayProperty;
+using Alembic::Abc::OInt32ArrayProperty;
+using Alembic::Abc::OStringArrayProperty;
+
+namespace blender::io::alembic {
+
+CustomPropertiesExporter::CustomPropertiesExporter(ABCAbstractWriter *owner) : owner_(owner)
+{
+}
+
+CustomPropertiesExporter::~CustomPropertiesExporter()
+{
+}
+
+void CustomPropertiesExporter::write_all(const IDProperty *group)
+{
+ if (group == nullptr) {
+ return;
+ }
+ BLI_assert(group->type == IDP_GROUP);
+
+ /* Loop over the properties, just like IDP_foreach_property() does, but without the recursion. */
+ LISTBASE_FOREACH (IDProperty *, id_property, &group->data.group) {
+ if (STREQ(id_property->name, "_RNA_UI")) {
+ continue;
+ }
+ write(id_property);
+ }
+}
+
+void CustomPropertiesExporter::write(const IDProperty *id_property)
+{
+ BLI_assert(id_property->name[0] != '\0');
+
+ switch (id_property->type) {
+ case IDP_STRING: {
+ /* The Alembic library doesn't accept NULL-terminated character arrays. */
+ const std::string prop_value(IDP_String(id_property), id_property->len - 1);
+ set_scalar_property<OStringArrayProperty, std::string>(id_property->name, prop_value);
+ break;
+ }
+ case IDP_INT:
+ static_assert(sizeof(int) == sizeof(int32_t), "Expecting 'int' to be 32-bit");
+ set_scalar_property<OInt32ArrayProperty, int32_t>(id_property->name, IDP_Int(id_property));
+ break;
+ case IDP_FLOAT:
+ set_scalar_property<OFloatArrayProperty, float>(id_property->name, IDP_Float(id_property));
+ break;
+ case IDP_DOUBLE:
+ set_scalar_property<ODoubleArrayProperty, double>(id_property->name,
+ IDP_Double(id_property));
+ break;
+ case IDP_ARRAY:
+ write_array(id_property);
+ break;
+ case IDP_IDPARRAY:
+ write_idparray(id_property);
+ break;
+ }
+}
+
+void CustomPropertiesExporter::write_array(const IDProperty *id_property)
+{
+ BLI_assert(id_property->type == IDP_ARRAY);
+
+ switch (id_property->subtype) {
+ case IDP_INT: {
+ const int *array = (int *)IDP_Array(id_property);
+ static_assert(sizeof(int) == sizeof(int32_t), "Expecting 'int' to be 32-bit");
+ set_array_property<OInt32ArrayProperty, int32_t>(id_property->name, array, id_property->len);
+ break;
+ }
+ case IDP_FLOAT: {
+ const float *array = (float *)IDP_Array(id_property);
+ set_array_property<OFloatArrayProperty, float>(id_property->name, array, id_property->len);
+ break;
+ }
+ case IDP_DOUBLE: {
+ const double *array = (double *)IDP_Array(id_property);
+ set_array_property<ODoubleArrayProperty, double>(id_property->name, array, id_property->len);
+ break;
+ }
+ }
+}
+
+void CustomPropertiesExporter::write_idparray(const IDProperty *idp_array)
+{
+ BLI_assert(idp_array->type == IDP_IDPARRAY);
+
+ if (idp_array->len == 0) {
+ /* Don't bother writing dataless arrays. */
+ return;
+ }
+
+ IDProperty *idp_elements = (IDProperty *)IDP_Array(idp_array);
+
+#ifndef NDEBUG
+ /* Sanity check that all elements of the array have the same type.
+ * Blender should already enforce this, hence it's only used in debug mode. */
+ for (int i = 1; i < idp_array->len; i++) {
+ if (idp_elements[i].type == idp_elements[0].type) {
+ continue;
+ }
+ std::cerr << "Custom property " << idp_array->name << " has elements of varying type";
+ BLI_assert(!"Mixed type IDP_ARRAY custom property found");
+ }
+#endif
+
+ switch (idp_elements[0].type) {
+ case IDP_STRING:
+ write_idparray_of_strings(idp_array);
+ break;
+ case IDP_ARRAY:
+ write_idparray_of_numbers(idp_array);
+ break;
+ }
+}
+
+void CustomPropertiesExporter::write_idparray_of_strings(const IDProperty *idp_array)
+{
+ BLI_assert(idp_array->type == IDP_IDPARRAY);
+ BLI_assert(idp_array->len > 0);
+
+ /* Convert to an array of std::strings, because Alembic doesn't like zero-delimited strings. */
+ IDProperty *idp_elements = (IDProperty *)IDP_Array(idp_array);
+ std::vector<std::string> strings(idp_array->len);
+ for (int i = 0; i < idp_array->len; i++) {
+ BLI_assert(idp_elements[i].type == IDP_STRING);
+ strings[i] = IDP_String(&idp_elements[i]);
+ }
+
+ /* Alembic needs a pointer to the first value of the array. */
+ const std::string *array_of_strings = &strings[0];
+ set_array_property<OStringArrayProperty, std::string>(
+ idp_array->name, array_of_strings, strings.size());
+}
+
+void CustomPropertiesExporter::write_idparray_of_numbers(const IDProperty *idp_array)
+{
+ BLI_assert(idp_array->type == IDP_IDPARRAY);
+ BLI_assert(idp_array->len > 0);
+
+ /* This must be an array of arrays. */
+ IDProperty *idp_rows = (IDProperty *)IDP_Array(idp_array);
+ BLI_assert(idp_rows[0].type == IDP_ARRAY);
+
+ const int subtype = idp_rows[0].subtype;
+ if (!ELEM(subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE)) {
+ /* Non-numerical types are not supported. */
+ return;
+ }
+
+ switch (subtype) {
+ case IDP_INT:
+ static_assert(sizeof(int) == sizeof(int32_t), "Expecting 'int' to be 32-bit");
+ write_idparray_flattened_typed<OInt32ArrayProperty, int32_t>(idp_array);
+ break;
+ case IDP_FLOAT:
+ write_idparray_flattened_typed<OFloatArrayProperty, float>(idp_array);
+ break;
+ case IDP_DOUBLE:
+ write_idparray_flattened_typed<ODoubleArrayProperty, double>(idp_array);
+ break;
+ }
+}
+
+template<typename ABCPropertyType, typename BlenderValueType>
+void CustomPropertiesExporter::write_idparray_flattened_typed(const IDProperty *idp_array)
+{
+ BLI_assert(idp_array->type == IDP_IDPARRAY);
+ BLI_assert(idp_array->len > 0);
+
+ const IDProperty *idp_rows = (IDProperty *)IDP_Array(idp_array);
+ BLI_assert(idp_rows[0].type == IDP_ARRAY);
+ BLI_assert(ELEM(idp_rows[0].subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE));
+
+ const uint64_t num_rows = idp_array->len;
+ std::vector<BlenderValueType> matrix_values;
+ for (size_t row_idx = 0; row_idx < num_rows; ++row_idx) {
+ const BlenderValueType *row = (BlenderValueType *)IDP_Array(&idp_rows[row_idx]);
+ for (size_t col_idx = 0; col_idx < idp_rows[row_idx].len; col_idx++) {
+ matrix_values.push_back(row[col_idx]);
+ }
+ }
+
+ set_array_property<ABCPropertyType, BlenderValueType>(
+ idp_array->name, &matrix_values[0], matrix_values.size());
+}
+
+template<typename ABCPropertyType, typename BlenderValueType>
+void CustomPropertiesExporter::set_scalar_property(const StringRef property_name,
+ const BlenderValueType property_value)
+{
+ set_array_property<ABCPropertyType, BlenderValueType>(property_name, &property_value, 1);
+}
+
+template<typename ABCPropertyType, typename BlenderValueType>
+void CustomPropertiesExporter::set_array_property(const StringRef property_name,
+ const BlenderValueType *array_values,
+ const size_t num_array_items)
+{
+ auto create_callback = [this, property_name]() -> OArrayProperty {
+ return create_abc_property<ABCPropertyType>(property_name);
+ };
+
+ OArrayProperty array_prop = abc_properties_.lookup_or_add_cb(property_name, create_callback);
+ Alembic::Util::Dimensions array_dimensions(num_array_items);
+ ArraySample sample(array_values, array_prop.getDataType(), array_dimensions);
+ array_prop.set(sample);
+}
+
+template<typename ABCPropertyType>
+OArrayProperty CustomPropertiesExporter::create_abc_property(const StringRef property_name)
+{
+ /* Get the necessary info from our owner. */
+ OCompoundProperty abc_prop_for_custom_props = owner_->abc_prop_for_custom_props();
+ const uint32_t timesample_index = owner_->timesample_index();
+
+ /* Construct the Alembic property. */
+ ABCPropertyType abc_property(abc_prop_for_custom_props, property_name);
+ abc_property.setTimeSampling(timesample_index);
+ return abc_property;
+}
+
+} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/exporter/abc_custom_props.h b/source/blender/io/alembic/exporter/abc_custom_props.h
new file mode 100644
index 00000000000..d3f9b2fc43c
--- /dev/null
+++ b/source/blender/io/alembic/exporter/abc_custom_props.h
@@ -0,0 +1,96 @@
+/*
+ * 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) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup Alembic
+ */
+
+#pragma once
+
+#include <Alembic/Abc/OArrayProperty.h>
+#include <Alembic/Abc/OCompoundProperty.h>
+
+#include "BLI_map.hh"
+
+#include <memory>
+
+struct IDProperty;
+
+namespace blender::io::alembic {
+
+class ABCAbstractWriter;
+
+/* Write values of Custom Properties (a.k.a. ID Properties) to Alembic.
+ *
+ * Each Alembic Writer instance optionally has one CustomPropertiesExporter (CPE). This CPE not
+ * only writes the custom properties to Alembic, but also keeps references in memory so that the
+ * Alembic library doesn't prematurely finalize the data. */
+class CustomPropertiesExporter {
+ private:
+ /* Owner is used to get the OCompoundProperty and time sample index. The former should only be
+ * requested from the Alembic library when it's actually going to be used to add custom
+ * properties (otherwise an invalid Alembic file is written). */
+ ABCAbstractWriter *owner_;
+
+ /* The Compound Property that will contain the exported custom properties.
+ *
+ * Typically this the return value of abc_schema.getArbGeomParams() or
+ * abc_schema.getUserProperties(). */
+ Alembic::Abc::OCompoundProperty abc_compound_prop_;
+
+ /* Mapping from property name in Blender to property in Alembic.
+ * Here Blender does the same as other software (Maya, Houdini), and writes
+ * scalar properties as single-element arrays. */
+ Map<std::string, Alembic::Abc::OArrayProperty> abc_properties_;
+
+ public:
+ CustomPropertiesExporter(ABCAbstractWriter *owner);
+ virtual ~CustomPropertiesExporter();
+
+ void write_all(const IDProperty *group);
+
+ private:
+ void write(const IDProperty *id_property);
+ void write_array(const IDProperty *id_property);
+
+ /* IDProperty arrays are used to store arrays-of-arrays or arrays-of-strings. */
+ void write_idparray(const IDProperty *idp_array);
+ void write_idparray_of_strings(const IDProperty *idp_array);
+ void write_idparray_of_numbers(const IDProperty *idp_array);
+
+ /* Flatten an array-of-arrays into one long array, then write that.
+ * It is tempting to write an array of NxM numbers as a matrix, but there is
+ * no guarantee that the data actually represents a matrix. */
+ template<typename ABCPropertyType, typename BlenderValueType>
+ void write_idparray_flattened_typed(const IDProperty *idp_array);
+
+ /* Write a single scalar (i.e. non-array) property as single-value array. */
+ template<typename ABCPropertyType, typename BlenderValueType>
+ void set_scalar_property(StringRef property_name, const BlenderValueType property_value);
+
+ template<typename ABCPropertyType, typename BlenderValueType>
+ void set_array_property(StringRef property_name,
+ const BlenderValueType *array_values,
+ size_t num_array_items);
+
+ template<typename ABCPropertyType>
+ Alembic::Abc::OArrayProperty create_abc_property(StringRef property_name);
+};
+
+} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.cc b/source/blender/io/alembic/exporter/abc_writer_abstract.cc
index 0b08d8c4e58..e99048cc0ee 100644
--- a/source/blender/io/alembic/exporter/abc_writer_abstract.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_abstract.cc
@@ -59,6 +59,7 @@ void ABCAbstractWriter::write(HierarchyContext &context)
if (!frame_has_been_written_) {
is_animated_ = (args_.export_params->frame_start != args_.export_params->frame_end) &&
check_is_animated(context);
+ ensure_custom_properties_exporter(context);
}
else if (!is_animated_) {
/* A frame has already been written, and without animation one frame is enough. */
@@ -67,9 +68,49 @@ void ABCAbstractWriter::write(HierarchyContext &context)
do_write(context);
+ if (custom_props_) {
+ custom_props_->write_all(get_id_properties(context));
+ }
+
frame_has_been_written_ = true;
}
+void ABCAbstractWriter::ensure_custom_properties_exporter(const HierarchyContext &context)
+{
+ if (!args_.export_params->export_custom_properties) {
+ return;
+ }
+
+ if (custom_props_) {
+ /* Custom properties exporter already created. */
+ return;
+ }
+
+ /* Avoid creating a custom properties exporter if there are no custom properties to export. */
+ const IDProperty *id_properties = get_id_properties(context);
+ if (id_properties == nullptr || id_properties->len == 0) {
+ return;
+ }
+
+ custom_props_ = std::make_unique<CustomPropertiesExporter>(this);
+}
+
+const IDProperty *ABCAbstractWriter::get_id_properties(const HierarchyContext &context) const
+{
+ Object *object = context.object;
+ if (object->data == nullptr) {
+ return nullptr;
+ }
+
+ /* Most subclasses write object data, so default to the object data's ID properties. */
+ return static_cast<ID *>(object->data)->properties;
+}
+
+uint32_t ABCAbstractWriter::timesample_index() const
+{
+ return timesample_index_;
+}
+
const Imath::Box3d &ABCAbstractWriter::bounding_box() const
{
return bounding_box_;
diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.h b/source/blender/io/alembic/exporter/abc_writer_abstract.h
index 59c55330443..d23e69cf73e 100644
--- a/source/blender/io/alembic/exporter/abc_writer_abstract.h
+++ b/source/blender/io/alembic/exporter/abc_writer_abstract.h
@@ -19,6 +19,7 @@
#pragma once
#include "IO_abstract_hierarchy_iterator.h"
+#include "abc_custom_props.h"
#include "abc_hierarchy_iterator.h"
#include <Alembic/Abc/OObject.h>
@@ -27,6 +28,7 @@
#include "DEG_depsgraph_query.h"
#include "DNA_material_types.h"
+struct IDProperty;
struct Material;
struct Object;
@@ -44,6 +46,9 @@ class ABCAbstractWriter : public AbstractHierarchyWriter {
/* Visibility of this writer's data in Alembic. */
Alembic::Abc::OCharProperty abc_visibility_;
+ /* Optional writer for custom properties. */
+ std::unique_ptr<CustomPropertiesExporter> custom_props_;
+
public:
explicit ABCAbstractWriter(const ABCWriterConstructorArgs &args);
virtual ~ABCAbstractWriter();
@@ -59,6 +64,7 @@ class ABCAbstractWriter : public AbstractHierarchyWriter {
* Empty). */
virtual bool is_supported(const HierarchyContext *context) const;
+ uint32_t timesample_index() const;
const Imath::Box3d &bounding_box() const;
/* Called by AlembicHierarchyCreator after checking that the data is supported via
@@ -67,12 +73,47 @@ class ABCAbstractWriter : public AbstractHierarchyWriter {
virtual Alembic::Abc::OObject get_alembic_object() const = 0;
+ /* Return the Alembic object's CompoundProperty that'll contain the custom properties.
+ *
+ * This function is called whenever there are custom properties to be written to Alembic. It
+ * should call abc_schema_prop_for_custom_props() with the writer's Alembic schema object.
+ *
+ * If custom properties are not supported by a specific subclass, it should return an empty
+ * OCompoundProperty() and override ensure_custom_properties_exporter() to do nothing.
+ */
+ virtual Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() = 0;
+
protected:
virtual void do_write(HierarchyContext &context) = 0;
virtual void update_bounding_box(Object *object);
+ /* Return ID properties of whatever ID datablock is written by this writer. Defaults to the
+ * properties of the object data. Can return nullptr if no custom properties are to be written.
+ */
+ virtual const IDProperty *get_id_properties(const HierarchyContext &context) const;
+
+ virtual void ensure_custom_properties_exporter(const HierarchyContext &context);
+
void write_visibility(const HierarchyContext &context);
+
+ /* Return the Alembic schema's compound property, which will be used for writing custom
+ * properties.
+ *
+ * This can return either abc_schema.getUserProperties() or abc_schema.getArbGeomParams(). The
+ * former only holds values similar to Blender's custom properties, whereas the latter can also
+ * specify that certain custom properties vary per mesh component (so per face, vertex, etc.). As
+ * such, .userProperties is more suitable for custom properties. However, Maya, Houdini use
+ * .arbGeomParams for custom data.
+ *
+ * Because of this, the code uses this templated function so that there is one place that
+ * determines where custom properties are exporter to.
+ */
+ template<typename T>
+ Alembic::Abc::OCompoundProperty abc_schema_prop_for_custom_props(T abc_schema)
+ {
+ return abc_schema.getUserProperties();
+ }
};
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/exporter/abc_writer_camera.cc b/source/blender/io/alembic/exporter/abc_writer_camera.cc
index 0ce6c3dc07f..82a741699e4 100644
--- a/source/blender/io/alembic/exporter/abc_writer_camera.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_camera.cc
@@ -65,6 +65,11 @@ Alembic::Abc::OObject ABCCameraWriter::get_alembic_object() const
return abc_camera_;
}
+Alembic::Abc::OCompoundProperty ABCCameraWriter::abc_prop_for_custom_props()
+{
+ return abc_schema_prop_for_custom_props(abc_camera_schema_);
+}
+
void ABCCameraWriter::do_write(HierarchyContext &context)
{
Camera *cam = static_cast<Camera *>(context.object->data);
diff --git a/source/blender/io/alembic/exporter/abc_writer_camera.h b/source/blender/io/alembic/exporter/abc_writer_camera.h
index 1b3e5898517..41885ed66d6 100644
--- a/source/blender/io/alembic/exporter/abc_writer_camera.h
+++ b/source/blender/io/alembic/exporter/abc_writer_camera.h
@@ -43,6 +43,7 @@ class ABCCameraWriter : public ABCAbstractWriter {
protected:
virtual bool is_supported(const HierarchyContext *context) const override;
virtual void do_write(HierarchyContext &context) override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
};
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/exporter/abc_writer_curves.cc b/source/blender/io/alembic/exporter/abc_writer_curves.cc
index 6a12e4c59f3..b57af345a3c 100644
--- a/source/blender/io/alembic/exporter/abc_writer_curves.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_curves.cc
@@ -66,6 +66,11 @@ Alembic::Abc::OObject ABCCurveWriter::get_alembic_object() const
return abc_curve_;
}
+Alembic::Abc::OCompoundProperty ABCCurveWriter::abc_prop_for_custom_props()
+{
+ return abc_schema_prop_for_custom_props(abc_curve_schema_);
+}
+
void ABCCurveWriter::do_write(HierarchyContext &context)
{
Curve *curve = static_cast<Curve *>(context.object->data);
diff --git a/source/blender/io/alembic/exporter/abc_writer_curves.h b/source/blender/io/alembic/exporter/abc_writer_curves.h
index d15f008f947..e210363557c 100644
--- a/source/blender/io/alembic/exporter/abc_writer_curves.h
+++ b/source/blender/io/alembic/exporter/abc_writer_curves.h
@@ -41,6 +41,7 @@ class ABCCurveWriter : public ABCAbstractWriter {
virtual void create_alembic_objects(const HierarchyContext *context) override;
virtual Alembic::Abc::OObject get_alembic_object() const override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
protected:
virtual void do_write(HierarchyContext &context) override;
diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc
index 80034245b84..072feb2a90a 100644
--- a/source/blender/io/alembic/exporter/abc_writer_hair.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc
@@ -62,6 +62,11 @@ Alembic::Abc::OObject ABCHairWriter::get_alembic_object() const
return abc_curves_;
}
+Alembic::Abc::OCompoundProperty ABCHairWriter::abc_prop_for_custom_props()
+{
+ return abc_schema_prop_for_custom_props(abc_curves_schema_);
+}
+
bool ABCHairWriter::check_is_animated(const HierarchyContext & /*context*/) const
{
/* We assume that hair particles are always animated. */
diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.h b/source/blender/io/alembic/exporter/abc_writer_hair.h
index f7d988ecbc4..3759ffa4310 100644
--- a/source/blender/io/alembic/exporter/abc_writer_hair.h
+++ b/source/blender/io/alembic/exporter/abc_writer_hair.h
@@ -44,6 +44,7 @@ class ABCHairWriter : public ABCAbstractWriter {
protected:
virtual void do_write(HierarchyContext &context) override;
virtual bool check_is_animated(const HierarchyContext &context) const override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
private:
void write_hair_sample(const HierarchyContext &context,
diff --git a/source/blender/io/alembic/exporter/abc_writer_instance.cc b/source/blender/io/alembic/exporter/abc_writer_instance.cc
index 14c65e2a2e2..7f3b044cb8b 100644
--- a/source/blender/io/alembic/exporter/abc_writer_instance.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_instance.cc
@@ -50,6 +50,16 @@ void ABCInstanceWriter::create_alembic_objects(const HierarchyContext *context)
CLOG_INFO(&LOG, 2, "exporting instance %s", args_.abc_path.c_str());
}
+void ABCInstanceWriter::ensure_custom_properties_exporter(const HierarchyContext & /*context*/)
+{
+ /* Intentionally do nothing. Instances should not have their own custom properties. */
+}
+
+Alembic::Abc::OCompoundProperty ABCInstanceWriter::abc_prop_for_custom_props()
+{
+ return Alembic::Abc::OCompoundProperty();
+}
+
OObject ABCInstanceWriter::get_alembic_object() const
{
/* There is no OObject for an instance. */
diff --git a/source/blender/io/alembic/exporter/abc_writer_instance.h b/source/blender/io/alembic/exporter/abc_writer_instance.h
index 067c4af7aed..f7d6450055a 100644
--- a/source/blender/io/alembic/exporter/abc_writer_instance.h
+++ b/source/blender/io/alembic/exporter/abc_writer_instance.h
@@ -39,6 +39,8 @@ class ABCInstanceWriter : public ABCAbstractWriter {
protected:
virtual bool is_supported(const HierarchyContext *context) const override;
virtual void do_write(HierarchyContext &context) override;
+ void ensure_custom_properties_exporter(const HierarchyContext &context) override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
};
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index b762ad47932..fbc662113cc 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -125,6 +125,14 @@ Alembic::Abc::OObject ABCGenericMeshWriter::get_alembic_object() const
return abc_poly_mesh_;
}
+Alembic::Abc::OCompoundProperty ABCGenericMeshWriter::abc_prop_for_custom_props()
+{
+ if (is_subd_) {
+ return abc_schema_prop_for_custom_props(abc_subdiv_schema_);
+ }
+ return abc_schema_prop_for_custom_props(abc_poly_mesh_schema_);
+}
+
bool ABCGenericMeshWriter::export_as_subdivision_surface(Object *ob_eval) const
{
ModifierData *md = static_cast<ModifierData *>(ob_eval->modifiers.last);
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.h b/source/blender/io/alembic/exporter/abc_writer_mesh.h
index 956587df7c0..fdf2d3cc1e3 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.h
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.h
@@ -55,6 +55,7 @@ class ABCGenericMeshWriter : public ABCAbstractWriter {
virtual void create_alembic_objects(const HierarchyContext *context) override;
virtual Alembic::Abc::OObject get_alembic_object() const override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
protected:
virtual bool is_supported(const HierarchyContext *context) const override;
diff --git a/source/blender/io/alembic/exporter/abc_writer_nurbs.cc b/source/blender/io/alembic/exporter/abc_writer_nurbs.cc
index de1870fefd9..7595a0eba63 100644
--- a/source/blender/io/alembic/exporter/abc_writer_nurbs.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_nurbs.cc
@@ -78,6 +78,17 @@ OObject ABCNurbsWriter::get_alembic_object() const
return abc_nurbs_[0];
}
+Alembic::Abc::OCompoundProperty ABCNurbsWriter::abc_prop_for_custom_props()
+{
+ if (abc_nurbs_.empty()) {
+ return Alembic::Abc::OCompoundProperty();
+ }
+
+ /* A single NURBS object in Blender is expanded to multiple curves in Alembic.
+ * Just store the custom properties on the first one for simplicity. */
+ return abc_schema_prop_for_custom_props(abc_nurbs_schemas_[0]);
+}
+
bool ABCNurbsWriter::check_is_animated(const HierarchyContext &context) const
{
/* Check if object has shape keys. */
diff --git a/source/blender/io/alembic/exporter/abc_writer_nurbs.h b/source/blender/io/alembic/exporter/abc_writer_nurbs.h
index 691390ffc9f..0f206d34682 100644
--- a/source/blender/io/alembic/exporter/abc_writer_nurbs.h
+++ b/source/blender/io/alembic/exporter/abc_writer_nurbs.h
@@ -40,6 +40,7 @@ class ABCNurbsWriter : public ABCAbstractWriter {
virtual bool is_supported(const HierarchyContext *context) const override;
virtual void do_write(HierarchyContext &context) override;
virtual bool check_is_animated(const HierarchyContext &context) const override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
};
class ABCNurbsMeshWriter : public ABCGenericMeshWriter {
diff --git a/source/blender/io/alembic/exporter/abc_writer_points.cc b/source/blender/io/alembic/exporter/abc_writer_points.cc
index 83d33577b3b..557f580e8aa 100644
--- a/source/blender/io/alembic/exporter/abc_writer_points.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_points.cc
@@ -58,6 +58,11 @@ Alembic::Abc::OObject ABCPointsWriter::get_alembic_object() const
return abc_points_;
}
+Alembic::Abc::OCompoundProperty ABCPointsWriter::abc_prop_for_custom_props()
+{
+ return abc_schema_prop_for_custom_props(abc_points_schema_);
+}
+
bool ABCPointsWriter::is_supported(const HierarchyContext *context) const
{
return ELEM(context->particle_system->part->type,
diff --git a/source/blender/io/alembic/exporter/abc_writer_points.h b/source/blender/io/alembic/exporter/abc_writer_points.h
index fec5e84f3f2..0447c41db3e 100644
--- a/source/blender/io/alembic/exporter/abc_writer_points.h
+++ b/source/blender/io/alembic/exporter/abc_writer_points.h
@@ -37,6 +37,7 @@ class ABCPointsWriter : public ABCAbstractWriter {
virtual void create_alembic_objects(const HierarchyContext *context) override;
virtual Alembic::Abc::OObject get_alembic_object() const override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
virtual bool is_supported(const HierarchyContext *context) const override;
diff --git a/source/blender/io/alembic/exporter/abc_writer_transform.cc b/source/blender/io/alembic/exporter/abc_writer_transform.cc
index a72a6b47aa9..79e460e56e9 100644
--- a/source/blender/io/alembic/exporter/abc_writer_transform.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_transform.cc
@@ -53,6 +53,17 @@ void ABCTransformWriter::create_alembic_objects(const HierarchyContext * /*conte
abc_xform_schema_ = abc_xform_.getSchema();
}
+Alembic::Abc::OCompoundProperty ABCTransformWriter::abc_prop_for_custom_props()
+{
+ return abc_schema_prop_for_custom_props<OXformSchema>(abc_xform_schema_);
+}
+
+const IDProperty *ABCTransformWriter::get_id_properties(const HierarchyContext &context) const
+{
+ const Object *object = context.object;
+ return object->id.properties;
+}
+
void ABCTransformWriter::do_write(HierarchyContext &context)
{
float parent_relative_matrix[4][4]; // The object matrix relative to the parent.
diff --git a/source/blender/io/alembic/exporter/abc_writer_transform.h b/source/blender/io/alembic/exporter/abc_writer_transform.h
index a334fe610ee..4542b9de506 100644
--- a/source/blender/io/alembic/exporter/abc_writer_transform.h
+++ b/source/blender/io/alembic/exporter/abc_writer_transform.h
@@ -21,6 +21,8 @@
#include "abc_writer_abstract.h"
+#include <memory>
+
#include <Alembic/AbcGeom/OXform.h>
namespace blender::io::alembic {
@@ -38,6 +40,8 @@ class ABCTransformWriter : public ABCAbstractWriter {
virtual void do_write(HierarchyContext &context) override;
virtual bool check_is_animated(const HierarchyContext &context) const override;
virtual Alembic::Abc::OObject get_alembic_object() const override;
+ const IDProperty *get_id_properties(const HierarchyContext &context) const override;
+ Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
};
} // namespace blender::io::alembic