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
path: root/source
diff options
context:
space:
mode:
authorBenjamin Skinner <benjamin.skinner96@gmail.com>2020-11-17 18:43:35 +0300
committermakowalski <makowalski@nvidia.com>2021-01-16 06:19:32 +0300
commit1e5e81a873874ac23ed390292221c9745c0bfc2b (patch)
tree9c8885c32cea0ddf7e5269f23c4147056d451e63 /source
parent3cc1bcce4ff7417bd0659e1171fd370e29385fc2 (diff)
Initial USD Import open sourcing.
Cherry-picked commit of Tangent Animation's USD importer from branch ta-usd-import in https://github.com/tangent-opensource/blender.git.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/CMakeLists.txt7
-rw-r--r--source/blender/blenkernel/intern/cachefile.c231
-rw-r--r--source/blender/blenkernel/intern/constraint.c21
-rw-r--r--source/blender/editors/io/io_ops.c1
-rw-r--r--source/blender/editors/io/io_usd.c290
-rw-r--r--source/blender/editors/io/io_usd.h3
-rw-r--r--source/blender/io/alembic/ABC_alembic.h8
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc28
-rw-r--r--source/blender/io/usd/CMakeLists.txt26
-rw-r--r--source/blender/io/usd/intern/usd_capi.cc502
-rw-r--r--source/blender/io/usd/intern/usd_reader_camera.cc103
-rw-r--r--source/blender/io/usd/intern/usd_reader_camera.h42
-rw-r--r--source/blender/io/usd/intern/usd_reader_curve.cc268
-rw-r--r--source/blender/io/usd/intern/usd_reader_curve.h58
-rw-r--r--source/blender/io/usd/intern/usd_reader_geom.cc111
-rw-r--r--source/blender/io/usd/intern/usd_reader_geom.h57
-rw-r--r--source/blender/io/usd/intern/usd_reader_light.cc198
-rw-r--r--source/blender/io/usd/intern/usd_reader_light.h42
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc740
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h98
-rw-r--r--source/blender/io/usd/intern/usd_reader_nurbs.cc273
-rw-r--r--source/blender/io/usd/intern/usd_reader_nurbs.h58
-rw-r--r--source/blender/io/usd/intern/usd_reader_prim.cc112
-rw-r--r--source/blender/io/usd/intern/usd_reader_prim.h239
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.cc153
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.h91
-rw-r--r--source/blender/io/usd/intern/usd_reader_volume.cc126
-rw-r--r--source/blender/io/usd/intern/usd_reader_volume.h46
-rw-r--r--source/blender/io/usd/intern/usd_reader_xform.cc120
-rw-r--r--source/blender/io/usd/intern/usd_reader_xform.h44
-rw-r--r--source/blender/io/usd/intern/usd_util.cc149
-rw-r--r--source/blender/io/usd/intern/usd_util.h59
-rw-r--r--source/blender/io/usd/usd.h63
-rw-r--r--source/blender/makesdna/DNA_cachefile_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h27
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h11
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h6
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c12
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c4
-rw-r--r--source/blender/modifiers/CMakeLists.txt10
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c85
41 files changed, 4422 insertions, 101 deletions
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 82f985a3227..3a7715a1d33 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -668,6 +668,13 @@ if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
endif()
+if(WITH_USD)
+ list(APPEND INC
+ ../io/usd
+ )
+ add_definitions(-DWITH_USD)
+endif()
+
if(WITH_OPENSUBDIV)
list(APPEND INC_SYS
${OPENSUBDIV_INCLUDE_DIRS}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index d6c31809a2e..fa11c43769c 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -55,6 +55,10 @@
# include "ABC_alembic.h"
#endif
+#ifdef WITH_USD
+# include "usd.h"
+#endif
+
static void cachefile_handle_free(CacheFile *cache_file);
static void cache_file_init_data(ID *id)
@@ -162,89 +166,178 @@ void BKE_cachefile_reader_open(CacheFile *cache_file,
Object *object,
const char *object_path)
{
+ switch (cache_file->type) {
#ifdef WITH_ALEMBIC
- BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ case CACHEFILE_TYPE_ALEMBIC:
+ BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
- if (cache_file->handle == NULL) {
- return;
- }
+ if (cache_file->handle == NULL) {
+ return;
+ }
- /* Open Alembic cache reader. */
- *reader = CacheReader_open_alembic_object(cache_file->handle, *reader, object, object_path);
+ /* Open Alembic cache reader. */
+ *reader = CacheReader_open_alembic_object(
+ (CacheArchiveHandle *)cache_file->handle, *reader, object, object_path);
+
+ /* Multiple modifiers and constraints can call this function concurrently. */
+ BLI_spin_lock(&spin);
+ if (*reader) {
+ /* Register in set so we can free it when the cache file changes. */
+ if (cache_file->handle_readers == NULL) {
+ cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
+ }
+ BLI_gset_reinsert(cache_file->handle_readers, reader, NULL);
+ }
+ else if (cache_file->handle_readers) {
+ /* Remove in case CacheReader_open_alembic_object free the existing reader. */
+ BLI_gset_remove(cache_file->handle_readers, reader, NULL);
+ }
+ BLI_spin_unlock(&spin);
+ break;
+#endif
+#ifdef WITH_USD
+ case CACHEFILE_TYPE_USD:
+ BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ if (cache_file->handle == NULL) {
+ return;
+ }
- /* Multiple modifiers and constraints can call this function concurrently. */
- BLI_spin_lock(&spin);
- if (*reader) {
- /* Register in set so we can free it when the cache file changes. */
- if (cache_file->handle_readers == NULL) {
- cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
- }
- BLI_gset_reinsert(cache_file->handle_readers, reader, NULL);
- }
- else if (cache_file->handle_readers) {
- /* Remove in case CacheReader_open_alembic_object free the existing reader. */
- BLI_gset_remove(cache_file->handle_readers, reader, NULL);
- }
- BLI_spin_unlock(&spin);
-#else
- UNUSED_VARS(cache_file, reader, object, object_path);
+ /* Open USD cache reader. */
+ *reader = CacheReader_open_usd_object(
+ (USDStageHandle *)cache_file->handle, *reader, object, object_path);
+ /* Multiple modifiers and constraints can call this function concurrently. */
+ BLI_spin_lock(&spin);
+ if (*reader) {
+ /* Register in set so we can free it when the cache file changes. */
+ if (cache_file->handle_readers == NULL) {
+ cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
+ }
+ BLI_gset_reinsert(cache_file->handle_readers, reader, NULL);
+ }
+ else if (cache_file->handle_readers) {
+ /* Remove in case CacheReader_open_usd_object free the existing reader. */
+ BLI_gset_remove(cache_file->handle_readers, reader, NULL);
+ }
+ BLI_spin_unlock(&spin);
+ break;
#endif
+ default:
+ UNUSED_VARS(cache_file, reader, object, object_path);
+ break;
+ }
}
void BKE_cachefile_reader_free(CacheFile *cache_file, struct CacheReader **reader)
{
+ switch (cache_file->type) {
#ifdef WITH_ALEMBIC
- if (*reader != NULL) {
- if (cache_file) {
- BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
- }
+ case CACHEFILE_TYPE_ALEMBIC:
+ if (*reader != NULL) {
+ if (cache_file) {
+ BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ }
- CacheReader_free(*reader);
- *reader = NULL;
+ CacheReader_free(*reader);
+ *reader = NULL;
- /* Multiple modifiers and constraints can call this function concurrently. */
- BLI_spin_lock(&spin);
- if (cache_file && cache_file->handle_readers) {
- BLI_gset_remove(cache_file->handle_readers, reader, NULL);
- }
- BLI_spin_unlock(&spin);
- }
-#else
- UNUSED_VARS(cache_file, reader);
+ /* Multiple modifiers and constraints can call this function concurrently. */
+ BLI_spin_lock(&spin);
+ if (cache_file && cache_file->handle_readers) {
+ BLI_gset_remove(cache_file->handle_readers, reader, NULL);
+ }
+ BLI_spin_unlock(&spin);
+ }
#endif
+#ifdef WITH_USD
+ case CACHEFILE_TYPE_USD:
+ if (*reader != NULL) {
+ if (cache_file) {
+ BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ }
+
+ USDCacheReader_free(*reader);
+ *reader = NULL;
+
+ /* Multiple modifiers and constraints can call this function concurrently. */
+ BLI_spin_lock(&spin);
+ if (cache_file && cache_file->handle_readers) {
+ BLI_gset_remove(cache_file->handle_readers, reader, NULL);
+ }
+ BLI_spin_unlock(&spin);
+ }
+ break;
+#endif
+ default:
+ UNUSED_VARS(cache_file, reader);
+ break;
+ }
}
static void cachefile_handle_free(CacheFile *cache_file)
{
+ switch (cache_file->type) {
#ifdef WITH_ALEMBIC
- /* Free readers in all modifiers and constraints that use the handle, before
- * we free the handle itself. */
- BLI_spin_lock(&spin);
- if (cache_file->handle_readers) {
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, cache_file->handle_readers) {
- struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter);
- if (*reader != NULL) {
- CacheReader_free(*reader);
- *reader = NULL;
+ case CACHEFILE_TYPE_ALEMBIC:
+ /* Free readers in all modifiers and constraints that use the handle, before
+ * we free the handle itself. */
+ BLI_spin_lock(&spin);
+ if (cache_file->handle_readers) {
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, cache_file->handle_readers) {
+ struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter);
+ if (*reader != NULL) {
+ CacheReader_free(*reader);
+ *reader = NULL;
+ }
+ }
+
+ BLI_gset_free(cache_file->handle_readers, NULL);
+ cache_file->handle_readers = NULL;
}
- }
+ BLI_spin_unlock(&spin);
- BLI_gset_free(cache_file->handle_readers, NULL);
- cache_file->handle_readers = NULL;
- }
- BLI_spin_unlock(&spin);
+ /* Free handle. */
+ if (cache_file->handle) {
+ ABC_free_handle((CacheArchiveHandle *)cache_file->handle);
+ cache_file->handle = NULL;
+ }
- /* Free handle. */
- if (cache_file->handle) {
- ABC_free_handle(cache_file->handle);
- cache_file->handle = NULL;
- }
+ cache_file->handle_filepath[0] = '\0';
+ break;
+#endif
+#ifdef WITH_USD
+ case CACHEFILE_TYPE_USD:
+ /* Free readers in all modifiers and constraints that use the handle, before
+ * we free the handle itself. */
+ BLI_spin_lock(&spin);
+ if (cache_file->handle_readers) {
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, cache_file->handle_readers) {
+ struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter);
+ if (*reader != NULL) {
+ USDCacheReader_free(*reader);
+ *reader = NULL;
+ }
+ }
+
+ BLI_gset_free(cache_file->handle_readers, NULL);
+ cache_file->handle_readers = NULL;
+ }
+ BLI_spin_unlock(&spin);
- cache_file->handle_filepath[0] = '\0';
-#else
- UNUSED_VARS(cache_file);
+ /* Free handle. */
+ if (cache_file->handle) {
+ USD_free_handle((USDStageHandle *)cache_file->handle);
+ cache_file->handle = NULL;
+ }
+
+ cache_file->handle_filepath[0] = '\0';
+ break;
#endif
+ default:
+ UNUSED_VARS(cache_file);
+ break;
+ }
}
void *BKE_cachefile_add(Main *bmain, const char *name)
@@ -284,8 +377,20 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file
BLI_freelistN(&cache_file->object_paths);
#ifdef WITH_ALEMBIC
- cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths);
- BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
+ if (BLI_path_extension_check_glob(filepath, "*abc")) {
+ cache_file->type = CACHEFILE_TYPE_ALEMBIC;
+ cache_file->handle = (CacheArchiveHandle *)ABC_create_handle(
+ bmain, filepath, &cache_file->object_paths);
+ BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
+ }
+#endif
+#ifdef WITH_USD
+ if (BLI_path_extension_check_glob(filepath, "*.usd;*.usda;*.usdc;*.usdz")) {
+ cache_file->type = CACHEFILE_TYPE_USD;
+ cache_file->handle = (CacheArchiveHandle *)USD_create_handle(
+ bmain, filepath, &cache_file->object_paths);
+ BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
+ }
#endif
if (DEG_is_active(depsgraph)) {
@@ -330,4 +435,4 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c
const float time_offset = cache_file->frame_offset / fps;
const float frame = (cache_file->override_frame ? cache_file->frame : time);
return cache_file->is_sequence ? frame : frame / fps - time_offset;
-}
+} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index b6f84dfc42f..7b5ac10f86e 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -95,6 +95,10 @@
# include "ABC_alembic.h"
#endif
+#ifdef WITH_USD
+# include "usd.h"
+#endif
+
/* ---------------------------------------------------------------------------- */
/* Useful macros for testing various common flag combinations */
@@ -5290,7 +5294,7 @@ static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, vo
static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
-#ifdef WITH_ALEMBIC
+#if defined(WITH_ALEMBIC) || defined(WITH_USD)
bTransformCacheConstraint *data = con->data;
Scene *scene = cob->scene;
@@ -5308,7 +5312,20 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
BKE_cachefile_reader_open(cache_file, &data->reader, cob->ob, data->object_path);
}
- ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
+ switch (cache_file->type) {
+# ifdef WITH_ALEMBIC
+ case CACHEFILE_TYPE_ALEMBIC:
+ ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
+ break;
+# endif
+# ifdef WITH_USD
+ case CACHEFILE_TYPE_USD:
+ USD_get_transform(data->reader, cob->matrix, time * FPS, cache_file->scale);
+ break;
+# endif
+ default:
+ break;
+ }
#else
UNUSED_VARS(con, cob);
#endif
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index acb511a414d..b4985f7fccf 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -51,6 +51,7 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_alembic_export);
#endif
#ifdef WITH_USD
+ WM_operatortype_append(WM_OT_usd_import);
WM_operatortype_append(WM_OT_usd_export);
#endif
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 0eadb38abb5..cb75e0d524b 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -22,23 +22,30 @@
*/
#ifdef WITH_USD
+# include <string.h>
# include "DNA_space_types.h"
+# include "DNA_modifier_types.h"
# include "BKE_context.h"
# include "BKE_main.h"
# include "BKE_report.h"
+# include "BLI_blenlib.h"
# include "BLI_path_util.h"
# include "BLI_string.h"
# include "BLI_utildefines.h"
# include "BLT_translation.h"
+# include "ED_object.h"
+
# include "MEM_guardedalloc.h"
# include "RNA_access.h"
# include "RNA_define.h"
+# include "RNA_enum_types.h"
+
# include "UI_interface.h"
# include "UI_resources.h"
@@ -50,6 +57,8 @@
# include "io_usd.h"
# include "usd.h"
+# include "stdio.h"
+
const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
{DAG_EVAL_RENDER,
"RENDER",
@@ -64,6 +73,16 @@ const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_usd_import_read_flags[] = {
+ {MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""},
+ {MOD_MESHSEQ_READ_POLY, "POLY", 0, "Faces", ""},
+ {MOD_MESHSEQ_READ_UV, "UV", 0, "UV", ""},
+ {MOD_MESHSEQ_READ_COLOR, "COLOR", 0, "Color", ""},
+ {MOD_MESHSEQ_READ_ATTR, "ATTR", 0, "Attributes", ""},
+ {MOD_MESHSEQ_READ_VELS, "VELS", 0, "Velocities", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
* This is set when the operator is invoked, and not set when it is only executed. */
enum { AS_BACKGROUND_JOB = 1 };
@@ -242,4 +261,275 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
"are different settings for viewport and rendering");
}
+/* ====== USD Import ====== */
+
+static int wm_usd_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "as_background_job")) {
+ RNA_boolean_set(op->ptr, "as_background_job", true);
+ }
+ return WM_operator_filesel(C, op, event);
+}
+
+static int wm_usd_import_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ const float scale = RNA_float_get(op->ptr, "scale");
+ const float vel_scale = RNA_float_get(op->ptr, "vel_scale");
+ const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
+ const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
+ const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
+ const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
+ const char global_read_flag = RNA_enum_get(op->ptr, "global_read_flag");
+
+ const bool import_cameras = RNA_boolean_get(op->ptr, "import_cameras");
+ const bool import_curves = RNA_boolean_get(op->ptr, "import_curves");
+ const bool import_lights = RNA_boolean_get(op->ptr, "import_lights");
+ const bool import_materials = RNA_boolean_get(op->ptr, "import_materials");
+ const bool import_meshes = RNA_boolean_get(op->ptr, "import_meshes");
+ const bool import_volumes = RNA_boolean_get(op->ptr, "import_volumes");
+
+ const bool import_subdiv = RNA_boolean_get(op->ptr, "import_subdiv");
+
+ const bool create_collection = RNA_boolean_get(op->ptr, "create_collection");
+
+ char *prim_path_mask = malloc(1024);
+ RNA_string_get(op->ptr, "prim_path_mask", prim_path_mask);
+
+ int offset = 0;
+ int sequence_len = 1;
+
+ if (is_sequence) {
+ // @TODO: Not Implemented
+ /*sequence_len = get_sequence_len(filename, &offset);
+ if (sequence_len < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to determine ABC sequence length");
+ return OPERATOR_CANCELLED;
+ }*/
+ }
+
+ /* Switch out of edit mode to avoid being stuck in it (T54326). */
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit) {
+ ED_object_mode_toggle(C, OB_MODE_EDIT);
+ }
+
+ struct USDImportParams params = {
+ scale,
+ vel_scale,
+ is_sequence,
+ set_frame_range,
+ sequence_len,
+ offset,
+ validate_meshes,
+ global_read_flag,
+ import_cameras,
+ import_curves,
+ import_lights,
+ import_materials,
+ import_meshes,
+ import_volumes,
+ prim_path_mask,
+ import_subdiv,
+ create_collection,
+ };
+
+ bool ok = USD_import(C, filename, &params, as_background_job);
+
+ return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ struct PointerRNA *ptr = op->ptr;
+
+ uiLayoutSetPropSep(layout, false);
+
+ uiLayout *box = uiLayoutBox(layout);
+ uiLayout *row = uiLayoutRow(box, false);
+
+ uiItemL(box, IFACE_("USD Import"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Global Read Flag:"), ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, ptr, "global_read_flag", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, ptr, "scale", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, ptr, "vel_scale", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Options:"), ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, ptr, "relative_path", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, ptr, "set_frame_range", 0, NULL, ICON_NONE);
+
+ // TODO: Not supported
+ // row = uiLayoutRow(box, false);
+ // uiItemR(row, ptr, "is_sequence", 0, NULL, ICON_NONE);
+
+ // row = uiLayoutRow(box, false);
+ // uiItemR(row, ptr, "validate_meshes", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, ptr, "import_subdiv", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, ptr, "create_collection", 0, NULL, ICON_NONE);
+
+ // row = uiLayoutRow(box, false);
+ // uiItemR(row, ptr, "prim_path_mask", 0, NULL, ICON_NONE);
+
+ uiLayout *prim_path_mask_box = uiLayoutBox(box);
+ row = uiLayoutRow(prim_path_mask_box, false);
+ uiItemL(row, IFACE_("Prim Path Mask:"), ICON_NONE);
+
+ row = uiLayoutRow(prim_path_mask_box, false);
+ uiItemR(row, ptr, "prim_path_mask", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Primitive Types:"), ICON_OBJECT_DATA);
+ uiItemR(box, ptr, "import_cameras", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "import_curves", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "import_lights", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "import_materials", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "import_meshes", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "import_volumes", 0, NULL, ICON_NONE);
+}
+
+void WM_OT_usd_import(struct wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Import USD";
+ ot->description = "Import USD stage into current scene";
+ ot->idname = "WM_OT_usd_import";
+
+ ot->invoke = wm_usd_import_invoke;
+ ot->exec = wm_usd_import_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_usd_import_draw;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_USD,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ RNA_def_float(
+ ot->srna,
+ "scale",
+ 1.0f,
+ 0.0001f,
+ 1000.0f,
+ "Scale",
+ "Value by which to enlarge or shrink the objects with respect to the world's origin",
+ 0.0001f,
+ 1000.0f);
+ RNA_def_float(ot->srna,
+ "vel_scale",
+ 1.0f,
+ 0.0001f,
+ 1000.0f,
+ "Velocity Scale",
+ "Amount to scale velocity",
+ 0.0001f,
+ 1000.0f);
+
+ RNA_def_boolean(
+ ot->srna,
+ "set_frame_range",
+ true,
+ "Set Frame Range",
+ "If checked, update scene's start and end frame to match those of the USD archive");
+
+ RNA_def_boolean(ot->srna,
+ "validate_meshes",
+ 0,
+ "Validate Meshes",
+ "Check imported mesh objects for invalid data (slow)");
+
+ RNA_def_boolean(ot->srna,
+ "is_sequence",
+ false,
+ "Is Sequence",
+ "Only set to true if the cache is split into separate files. (UNSUPPORTED)");
+
+ RNA_def_boolean(
+ ot->srna,
+ "as_background_job",
+ false,
+ "Run as Background Job",
+ "Enable this to run the export in the background, disable to block Blender while exporting. "
+ "This option is deprecated; EXECUTE this operator to run in the foreground, and INVOKE it "
+ "to run as a background job");
+
+ RNA_def_boolean(
+ ot->srna, "import_cameras", true, "Cameras", "When checked, all cameras will be imported");
+ RNA_def_boolean(
+ ot->srna, "import_curves", true, "Curves", "When checked, all curves will be imported");
+ RNA_def_boolean(
+ ot->srna, "import_lights", true, "Lights", "When checked, all lights will be imported");
+ RNA_def_boolean(ot->srna,
+ "import_materials",
+ true,
+ "Materials",
+ "When checked, all materials will be imported");
+ RNA_def_boolean(
+ ot->srna, "import_meshes", true, "Meshes", "When checked, all meshes will be imported");
+ RNA_def_boolean(ot->srna,
+ "import_volumes",
+ true,
+ "Volumes",
+ "(Tangent Specific) When checked, all volumes will be imported");
+
+ RNA_def_boolean(ot->srna,
+ "import_subdiv",
+ true,
+ "Import Subdiv Scheme",
+ "If enabled, subdiv surface modifiers will be created based on USD "
+ "SubdivisionScheme attribute");
+
+ RNA_def_boolean(ot->srna,
+ "create_collection",
+ false,
+ "Create Collection",
+ "If enabled, all import objects will be added to a new collection");
+
+ prop = RNA_def_enum(ot->srna,
+ "global_read_flag",
+ rna_enum_usd_import_read_flags,
+ 0,
+ "Flags",
+ "Set read flag for all usd import mesh sequence cache modifiers");
+
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_enum_default(prop, MOD_MESHSEQ_READ_ALL);
+
+ RNA_def_string(ot->srna,
+ "prim_path_mask",
+ NULL,
+ 1024,
+ "",
+ "If set, this will specify a specific primitive from the usd stage");
+}
+
#endif /* WITH_USD */
diff --git a/source/blender/editors/io/io_usd.h b/source/blender/editors/io/io_usd.h
index 671984b6f34..24de748285c 100644
--- a/source/blender/editors/io/io_usd.h
+++ b/source/blender/editors/io/io_usd.h
@@ -26,3 +26,6 @@
struct wmOperatorType;
void WM_OT_usd_export(struct wmOperatorType *ot);
+
+void WM_OT_usd_import(struct wmOperatorType *ot);
+
diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h
index 9785f6d68ab..9432e54346f 100644
--- a/source/blender/io/alembic/ABC_alembic.h
+++ b/source/blender/io/alembic/ABC_alembic.h
@@ -31,7 +31,7 @@ struct Object;
struct Scene;
struct bContext;
-typedef struct AbcArchiveHandle AbcArchiveHandle;
+typedef struct CacheArchiveHandle CacheArchiveHandle;
int ABC_get_version(void);
@@ -97,11 +97,11 @@ bool ABC_import(struct bContext *C,
bool validate_meshes,
bool as_background_job);
-AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
+CacheArchiveHandle *ABC_create_handle(struct Main *bmain,
const char *filename,
struct ListBase *object_paths);
-void ABC_free_handle(AbcArchiveHandle *handle);
+void ABC_free_handle(CacheArchiveHandle *handle);
void ABC_get_transform(struct CacheReader *reader,
float r_mat_world[4][4],
@@ -125,7 +125,7 @@ bool ABC_mesh_topology_changed(struct CacheReader *reader,
void CacheReader_incref(struct CacheReader *reader);
void CacheReader_free(struct CacheReader *reader);
-struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle,
+struct CacheReader *CacheReader_open_alembic_object(struct CacheArchiveHandle *handle,
struct CacheReader *reader,
struct Object *object,
const char *object_path);
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index ad5a258f80c..45ea4d2ed60 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -89,18 +89,14 @@ using Alembic::AbcMaterial::IMaterial;
using namespace blender::io::alembic;
-struct AbcArchiveHandle {
- int unused;
-};
-
-BLI_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle)
+BLI_INLINE ArchiveReader *archive_from_handle(CacheArchiveHandle *handle)
{
return reinterpret_cast<ArchiveReader *>(handle);
}
-BLI_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive)
+BLI_INLINE CacheArchiveHandle *handle_from_archive(ArchiveReader *archive)
{
- return reinterpret_cast<AbcArchiveHandle *>(archive);
+ return reinterpret_cast<CacheArchiveHandle *>(archive);
}
//#define USE_NURBS
@@ -150,8 +146,8 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
}
if (get_path) {
- void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath");
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void);
+ void *abc_path_void = MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath");
+ CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(abc_path_void);
BLI_strncpy(abc_path->path, object.getFullName().c_str(), sizeof(abc_path->path));
BLI_addtail(object_paths, abc_path);
@@ -160,9 +156,9 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
return parent_is_part_of_this_object;
}
-AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
- const char *filename,
- ListBase *object_paths)
+CacheArchiveHandle *ABC_create_handle(struct Main *bmain,
+ const char *filename,
+ ListBase *object_paths)
{
ArchiveReader *archive = new ArchiveReader(bmain, filename);
@@ -178,7 +174,7 @@ AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
return handle_from_archive(archive);
}
-void ABC_free_handle(AbcArchiveHandle *handle)
+void ABC_free_handle(CacheArchiveHandle *handle)
{
delete archive_from_handle(handle);
}
@@ -359,8 +355,8 @@ static std::pair<bool, AbcObjectReader *> visit_object(
readers.push_back(reader);
reader->incref();
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
- MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+ CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(
+ MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath"));
BLI_strncpy(abc_path->path, full_name.c_str(), sizeof(abc_path->path));
BLI_addtail(&settings.cache_file->object_paths, abc_path);
@@ -828,7 +824,7 @@ void CacheReader_incref(CacheReader *reader)
abc_reader->incref();
}
-CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle,
+CacheReader *CacheReader_open_alembic_object(CacheArchiveHandle *handle,
CacheReader *reader,
Object *object,
const char *object_path)
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index 79b15c60b94..46c2ac26e94 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -63,6 +63,19 @@ set(SRC
intern/usd_writer_metaball.cc
intern/usd_writer_transform.cc
+ intern/usd_util.cc
+
+ intern/usd_reader_camera.cc
+ intern/usd_reader_curve.cc
+ intern/usd_reader_geom.cc
+ intern/usd_reader_light.cc
+ intern/usd_reader_mesh.cc
+ intern/usd_reader_nurbs.cc
+ intern/usd_reader_prim.cc
+ intern/usd_reader_stage.cc
+ intern/usd_reader_xform.cc
+ intern/usd_reader_volume.cc
+
usd.h
intern/usd_exporter_context.h
intern/usd_hierarchy_iterator.h
@@ -73,6 +86,19 @@ set(SRC
intern/usd_writer_mesh.h
intern/usd_writer_metaball.h
intern/usd_writer_transform.h
+
+ intern/usd_util.h
+
+ intern/usd_reader_camera.h
+ intern/usd_reader_curve.h
+ intern/usd_reader_geom.h
+ intern/usd_reader_light.h
+ intern/usd_reader_mesh.h
+ intern/usd_reader_nurbs.h
+ intern/usd_reader_prim.h
+ intern/usd_reader_stage.h
+ intern/usd_reader_xform.h
+ intern/usd_reader_volume.h
)
set(LIB
diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc
index dc2b46e5cea..a91c41f7bac 100644
--- a/source/blender/io/usd/intern/usd_capi.cc
+++ b/source/blender/io/usd/intern/usd_capi.cc
@@ -19,11 +19,19 @@
#include "usd.h"
#include "usd_hierarchy_iterator.h"
+#include "usd_reader_mesh.h"
+#include "usd_reader_prim.h"
+#include "usd_reader_stage.h"
#include <pxr/base/plug/registry.h>
#include <pxr/pxr.h>
#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/metrics.h>
+#include <pxr/usd/usdGeom/scope.h>
#include <pxr/usd/usdGeom/tokens.h>
+#include <pxr/usd/usdGeom/xformCommonAPI.h>
+#include <pxr/usd/usdLux/domeLight.h>
+#include <pxr/usd/usdShade/materialBindingAPI.h>
#include "MEM_guardedalloc.h"
@@ -31,23 +39,80 @@
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_node_types.h"
#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
+#include "BKE_cachefile.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_scene.h"
+#include "BKE_world.h"
#include "BLI_fileops.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "usd_reader_geom.h"
+#include "usd_reader_prim.h"
+#include "usd_util.h"
+
+struct USDStageHandle {
+ CacheArchiveHandle base;
+};
+
namespace blender::io::usd {
+USDStageReader *archive_from_handle(USDStageHandle *handle)
+{
+ return reinterpret_cast<USDStageReader *>(handle);
+}
+
+USDStageReader *archive_from_handle(CacheArchiveHandle *handle)
+{
+ return reinterpret_cast<USDStageReader *>(handle);
+}
+
+USDStageHandle *handle_from_archive(USDStageReader *archive)
+{
+ return reinterpret_cast<USDStageHandle *>(archive);
+}
+
+static bool gather_objects_paths(const pxr::UsdPrim &object, ListBase *object_paths)
+{
+ if (!object.IsValid()) {
+ return false;
+ }
+
+ for (const pxr::UsdPrim &childPrim : object.GetChildren()) {
+ gather_objects_paths(childPrim, object_paths);
+ }
+
+ void *usd_path_void = MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath");
+ CacheObjectPath *usd_path = static_cast<CacheObjectPath *>(usd_path_void);
+
+ BLI_strncpy(usd_path->path, object.GetPrimPath().GetString().c_str(), sizeof(usd_path->path));
+ BLI_addtail(object_paths, usd_path);
+
+ return true;
+}
+
+/* ********************** Export file ********************** */
+
struct ExportJobData {
Main *bmain;
Depsgraph *depsgraph;
@@ -210,6 +275,7 @@ bool USD_export(bContext *C,
if (as_background_job) {
wmJob *wm_job = WM_jobs_get(
job->wm, CTX_wm_window(C), scene, "USD Export", WM_JOB_PROGRESS, WM_JOB_TYPE_ALEMBIC);
+ // TODO: Should create WM_JOB_TYPE_USD...
/* setup job */
WM_jobs_customdata_set(wm_job, job, MEM_freeN);
@@ -250,3 +316,439 @@ int USD_get_version(void)
*/
return PXR_VERSION;
}
+
+/* ********************** Import file ********************** */
+
+namespace USD {
+enum {
+ USD_NO_ERROR = 0,
+ USD_ARCHIVE_FAIL,
+};
+
+struct ImportJobData {
+ Main *bmain;
+ Scene *scene;
+ ViewLayer *view_layer;
+ wmWindowManager *wm;
+
+ char filename[1024];
+ USDImportParams params;
+ ImportSettings settings;
+
+ USDStageReader *archive;
+ std::vector<USDPrimReader *> readers;
+
+ short *stop;
+ short *do_update;
+ float *progress;
+
+ char error_code;
+ bool was_canceled;
+ bool import_ok;
+};
+
+static void import_startjob(void *customdata, short *stop, short *do_update, float *progress)
+{
+ WM_reportf(RPT_WARNING, "Import start job: %s", 0);
+ ImportJobData *data = static_cast<ImportJobData *>(customdata);
+
+ data->stop = stop;
+ data->do_update = do_update;
+ data->progress = progress;
+ data->was_canceled = false;
+
+ // G.is_rendering = true;
+ WM_set_locked_interface(data->wm, true);
+ G.is_break = false;
+
+ if (data->params.create_collection) {
+ char display_name[1024];
+ BLI_path_to_display_name(
+ display_name, strlen(data->filename), BLI_path_basename(data->filename));
+ Collection *import_collection = BKE_collection_add(
+ data->bmain, data->scene->master_collection, display_name);
+ id_fake_user_set(&import_collection->id);
+
+ DEG_id_tag_update(&import_collection->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(data->bmain);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ data->view_layer->active_collection = BKE_layer_collection_first_from_scene_collection(
+ data->view_layer, import_collection);
+ }
+
+ BLI_path_abs(data->filename, BKE_main_blendfile_path_from_global());
+ USDStageReader *archive = new USDStageReader(data->bmain, data->filename);
+
+ archive->params(data->params);
+ archive->settings(data->settings);
+
+ CacheFile *cache_file = static_cast<CacheFile *>(
+ BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename)));
+
+ /* Decrement the ID ref-count because it is going to be incremented for each
+ * modifier and constraint that it will be attached to, so since currently
+ * it is not used by anyone, its use count will off by one. */
+ id_us_min(&cache_file->id);
+
+ cache_file->is_sequence = data->params.is_sequence;
+ cache_file->scale = data->params.scale;
+ STRNCPY(cache_file->filepath, data->filename);
+
+ data->archive = archive;
+ data->settings.cache_file = cache_file;
+ data->settings.vel_scale = data->params.vel_scale;
+
+ *data->do_update = true;
+ *data->progress = 0.05f;
+
+ if (G.is_break) {
+ data->was_canceled = true;
+ return;
+ }
+
+ *data->do_update = true;
+ *data->progress = 0.1f;
+
+ Scene *scene = data->scene;
+
+ if (!archive->stage()) {
+ /* This happens when the USD JSON files cannot be found. When that happens,
+ * the USD library doesn't know it has the functionality to write USDA and
+ * USDC files, and creating a new UsdStage fails. */
+ WM_reportf(
+ RPT_ERROR, "USD Import: unable to find suitable USD plugin to read %s", data->filename);
+ data->import_ok = false;
+ return;
+ }
+
+ // Set up the stage for animated data.
+ if (data->params.set_frame_range) {
+ // archive->stage()->SetTimeCodesPerSecond(FPS);
+ scene->r.sfra = archive->stage()->GetStartTimeCode();
+ scene->r.efra = archive->stage()->GetEndTimeCode();
+ // archive->usd_stage->SetStartTimeCode(scene->r.sfra);
+ // usd_stage->SetEndTimeCode(scene->r.efra);
+ }
+
+ *data->progress = 0.15f;
+
+ data->readers = archive->collect_readers(data->bmain, data->params, data->settings);
+
+ *data->progress = 0.2f;
+
+ const float size = static_cast<float>(data->readers.size());
+ size_t i = 0;
+
+ std::vector<USDPrimReader *>::iterator iter;
+
+ /* Setup parenthood */
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ Object *ob = (*iter)->object();
+
+ USDPrimReader *reader = (*iter);
+ reader->readObjectData(data->bmain, 0.0);
+
+ USDPrimReader *parent = (*iter)->parent();
+
+ if (parent == NULL /*|| !reader->inherits_xform()*/) {
+ ob->parent = NULL;
+ }
+ else {
+ ob->parent = parent->object();
+ }
+
+ *data->progress = 0.2f + 0.8f * (++i / size);
+ *data->do_update = true;
+
+ if (G.is_break) {
+ data->was_canceled = true;
+ return;
+ }
+ }
+
+ data->import_ok = !data->was_canceled;
+
+ *progress = 1.0f;
+ *do_update = true;
+}
+
+static void import_endjob(void *customdata)
+{
+ WM_reportf(RPT_WARNING, "Import end job: %s", 0);
+
+ ImportJobData *data = static_cast<ImportJobData *>(customdata);
+
+ std::vector<USDPrimReader *>::iterator iter;
+
+ /* Delete objects on cancellation. */
+ if (data->was_canceled) {
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ Object *ob = (*iter)->object();
+
+ /* It's possible that cancellation occurred between the creation of
+ * the reader and the creation of the Blender object. */
+ if (ob == NULL) {
+ continue;
+ }
+
+ BKE_id_free_us(data->bmain, ob);
+ }
+ }
+ else {
+ /* Add object to scene. */
+ Base *base;
+ LayerCollection *lc;
+ ViewLayer *view_layer = data->view_layer;
+
+ BKE_view_layer_base_deselect_all(view_layer);
+
+ lc = BKE_layer_collection_get_active(view_layer);
+
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ Object *ob = (*iter)->object();
+
+ BKE_collection_object_add(data->bmain, lc->collection, ob);
+
+ base = BKE_view_layer_base_find(view_layer, ob);
+ /* TODO: is setting active needed? */
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+
+ DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update_ex(data->bmain,
+ &ob->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION |
+ ID_RECALC_BASE_FLAGS);
+ }
+
+ DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS);
+ DEG_relations_tag_update(data->bmain);
+ }
+
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ USDPrimReader *reader = *iter;
+ reader->decref();
+
+ if (reader->refcount() == 0) {
+ delete reader;
+ }
+ }
+
+ WM_set_locked_interface(data->wm, false);
+
+ switch (data->error_code) {
+ default:
+ case USD_NO_ERROR:
+ data->import_ok = !data->was_canceled;
+ break;
+ case USD_ARCHIVE_FAIL:
+ WM_report(RPT_ERROR, "Could not open USD archive for reading! See console for detail.");
+ break;
+ }
+
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
+}
+
+static void import_freejob(void *user_data)
+{
+ ImportJobData *data = static_cast<ImportJobData *>(user_data);
+
+ // delete data->archive;
+ delete data;
+}
+
+} // namespace USD
+
+bool USD_import(struct bContext *C,
+ const char *filepath,
+ const USDImportParams *params,
+ bool as_background_job)
+{
+ /* Using new here since MEM_* funcs do not call ctor to properly initialize
+ * data. */
+ USD::ImportJobData *job = new USD::ImportJobData();
+ // USD::ImportJobData *job = static_cast<USD::ImportJobData
+ // *>(MEM_mallocN(sizeof(USD::ImportJobData), "ImportJobData"));
+ job->bmain = CTX_data_main(C);
+ job->scene = CTX_data_scene(C);
+ job->view_layer = CTX_data_view_layer(C);
+ job->wm = CTX_wm_manager(C);
+ job->import_ok = false;
+ BLI_strncpy(job->filename, filepath, 1024);
+
+ job->settings.scale = params->scale;
+ job->settings.sequence_offset = params->offset;
+ job->settings.is_sequence = params->is_sequence;
+ job->settings.sequence_len = params->sequence_len;
+ job->settings.validate_meshes = params->validate_meshes;
+ job->settings.sequence_len = params->sequence_len;
+ job->error_code = USD::USD_NO_ERROR;
+ job->was_canceled = false;
+ job->archive = NULL;
+
+ job->params = *params;
+
+ G.is_break = false;
+
+ bool import_ok = false;
+ if (as_background_job) {
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "USD Import",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, USD::import_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, USD::import_startjob, NULL, NULL, USD::import_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+ else {
+ /* Fake a job context, so that we don't need NULL pointer checks while importing. */
+ short stop = 0, do_update = 0;
+ float progress = 0.f;
+
+ USD::import_startjob(job, &stop, &do_update, &progress);
+ USD::import_endjob(job);
+ import_ok = job->import_ok;
+
+ USD::import_freejob(job);
+ }
+
+ return import_ok;
+}
+
+static USDPrimReader *get_usd_reader(CacheReader *reader, Object *ob, const char **err_str)
+{
+ USDPrimReader *usd_reader = reinterpret_cast<USDPrimReader *>(reader);
+ pxr::UsdPrim iobject = usd_reader->prim();
+
+ if (!iobject.IsValid()) {
+ *err_str = "Invalid object: verify object path";
+ return NULL;
+ }
+
+ /*const ObjectHeader &header = iobject.getHeader();
+ if (!usd_reader->accepts_object_type(header, ob, err_str)) {*/
+ /* err_str is set by acceptsObjectType() */
+ /*return NULL;
+}*/
+
+ return usd_reader;
+}
+
+Mesh *USD_read_mesh(CacheReader *reader,
+ Object *ob,
+ Mesh *existing_mesh,
+ const float time,
+ const char **err_str,
+ int read_flag,
+ float vel_fac)
+{
+ USDGeomReader *usd_reader = reinterpret_cast<USDGeomReader *>(
+ get_usd_reader(reader, ob, err_str));
+ if (usd_reader == NULL) {
+ return NULL;
+ }
+
+ return usd_reader->read_mesh(existing_mesh, time, read_flag, vel_fac, err_str);
+}
+
+bool USD_mesh_topology_changed(
+ CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str)
+{
+ USDMeshReader *usd_reader = (USDMeshReader *)get_usd_reader(reader, ob, err_str);
+
+ if (usd_reader == NULL) {
+ return false;
+ }
+
+ return usd_reader->topology_changed(existing_mesh, time);
+}
+
+void USDCacheReader_incref(CacheReader *reader)
+{
+ USDPrimReader *usd_reader = reinterpret_cast<USDPrimReader *>(reader);
+ usd_reader->incref();
+}
+
+CacheReader *CacheReader_open_usd_object(USDStageHandle *handle,
+ CacheReader *reader,
+ Object *object,
+ const char *object_path)
+{
+ if (object_path[0] == '\0') {
+ return reader;
+ }
+
+ USD::USDStageReader *archive = USD::archive_from_handle(handle);
+
+ if (!archive || !archive->valid()) {
+ return reader;
+ }
+
+ pxr::UsdPrim prim = archive->stage()->GetPrimAtPath(pxr::SdfPath(object_path));
+
+ if (reader) {
+ USDCacheReader_free(reader);
+ }
+
+ // TODO: The handle does not have the proper import params or settings
+ USDPrimReader *usd_reader = USD::create_fake_reader(archive, prim);
+
+ if (usd_reader == NULL) {
+ /* This object is not supported */
+ return NULL;
+ }
+ usd_reader->object(object);
+ usd_reader->incref();
+
+ return reinterpret_cast<CacheReader *>(usd_reader);
+}
+
+void USDCacheReader_free(CacheReader *reader)
+{
+ USDPrimReader *usd_reader = reinterpret_cast<USDPrimReader *>(reader);
+ usd_reader->decref();
+
+ if (usd_reader->refcount() == 0) {
+ delete usd_reader;
+ }
+}
+
+USDStageHandle *USD_create_handle(struct Main *bmain, const char *filename, ListBase *object_paths)
+{
+ USD::USDStageReader *archive = new USD::USDStageReader(bmain, filename);
+
+ if (!archive->valid()) {
+ delete archive;
+ return NULL;
+ }
+
+ if (object_paths) {
+ USD::gather_objects_paths(archive->stage()->GetPseudoRoot(), object_paths);
+ }
+
+ return USD::handle_from_archive(archive);
+}
+
+void USD_free_handle(USDStageHandle *handle)
+{
+ USD::USDStageReader *archive = USD::archive_from_handle(handle);
+ delete archive;
+}
+
+void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale)
+{
+ if (!reader) {
+ return;
+ }
+ USDXformReader *usd_reader = reinterpret_cast<USDXformReader *>(reader);
+
+ bool is_constant = false;
+ usd_reader->read_matrix(r_mat, time, scale, is_constant);
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_camera.cc b/source/blender/io/usd/intern/usd_reader_camera.cc
new file mode 100644
index 00000000000..d76c2828d3a
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_camera.cc
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_camera.h"
+#include "usd_reader_prim.h"
+
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/pxr.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/camera.h>
+
+void USDCameraReader::createObject(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Creating blender camera for prim: %s", m_prim.GetPath().GetText());
+ Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_name.c_str()));
+
+ m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_name.c_str());
+ m_object->data = bcam;
+}
+
+void USDCameraReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ Camera *bcam = (Camera *)m_object->data;
+
+ pxr::UsdGeomCamera cam_prim = pxr::UsdGeomCamera::Get(m_stage, m_prim.GetPath());
+
+ pxr::VtValue val;
+ cam_prim.GetFocalLengthAttr().Get(&val, motionSampleTime);
+ pxr::VtValue verApOffset;
+ cam_prim.GetVerticalApertureOffsetAttr().Get(&verApOffset, motionSampleTime);
+ pxr::VtValue horApOffset;
+ cam_prim.GetHorizontalApertureOffsetAttr().Get(&horApOffset, motionSampleTime);
+ pxr::VtValue clippingRangeVal;
+ cam_prim.GetClippingRangeAttr().Get(&clippingRangeVal, motionSampleTime);
+ pxr::VtValue focalDistanceVal;
+ cam_prim.GetFocusDistanceAttr().Get(&focalDistanceVal, motionSampleTime);
+ pxr::VtValue fstopVal;
+ cam_prim.GetFStopAttr().Get(&fstopVal, motionSampleTime);
+ pxr::VtValue projectionVal;
+ cam_prim.GetProjectionAttr().Get(&projectionVal, motionSampleTime);
+ pxr::VtValue verAp;
+ cam_prim.GetVerticalApertureAttr().Get(&verAp, motionSampleTime);
+ pxr::VtValue horAp;
+ cam_prim.GetHorizontalApertureAttr().Get(&horAp, motionSampleTime);
+
+ bcam->lens = val.Get<float>();
+ // bcam->sensor_x = 0.0f;
+ // bcam->sensor_y = 0.0f;
+ bcam->shiftx = verApOffset.Get<float>();
+ bcam->shifty = horApOffset.Get<float>();
+
+ bcam->type = (projectionVal.Get<pxr::TfToken>().GetString() == "perspective") ? CAM_PERSP :
+ CAM_ORTHO;
+
+ bcam->clip_start = max_ff(0.1f, clippingRangeVal.Get<pxr::GfVec2f>()[0]);
+ bcam->clip_end = clippingRangeVal.Get<pxr::GfVec2f>()[1];
+
+ bcam->dof.focus_distance = focalDistanceVal.Get<float>();
+ bcam->dof.aperture_fstop = static_cast<float>(fstopVal.Get<float>());
+
+ if (bcam->type == CAM_ORTHO) {
+ bcam->ortho_scale = max_ff(verAp.Get<float>(), horAp.Get<float>());
+ }
+
+ USDXformReader::readObjectData(bmain, motionSampleTime);
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_camera.h b/source/blender/io/usd/intern/usd_reader_camera.h
new file mode 100644
index 00000000000..ac749ca2a4c
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_camera.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_CAMERA_H__
+#define __USD_READER_CAMERA_H__
+
+#include "usd.h"
+#include "usd_reader_xform.h"
+
+class USDCameraReader : public USDXformReader {
+
+ public:
+ USDCameraReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDXformReader(stage, object, import_params, settings)
+ {
+ }
+
+ void createObject(Main *bmain, double motionSampleTime) override;
+ void readObjectData(Main *bmain, double motionSampleTime) override;
+};
+
+#endif /* __USD_READER_CAMERA_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_curve.cc b/source/blender/io/usd/intern/usd_reader_curve.cc
new file mode 100644
index 00000000000..97acf29181d
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_curve.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.
+ */
+
+#include "usd_reader_curve.h"
+#include "usd_reader_prim.h"
+
+#include "MEM_guardedalloc.h"
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/base/vt/array.h>
+#include <pxr/base/vt/types.h>
+#include <pxr/base/vt/value.h>
+#include <pxr/pxr.h>
+#include <pxr/usd/sdf/assetPath.h>
+#include <pxr/usd/sdf/types.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/basisCurves.h>
+#include <pxr/usd/usdGeom/curves.h>
+
+void USDCurvesReader::createObject(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Creating blender curve for prim: %s", m_prim.GetPath().GetText());
+ m_curve = BKE_curve_add(bmain, m_name.c_str(), OB_CURVE);
+
+ m_curve->flag |= CU_DEFORM_FILL | CU_3D;
+ m_curve->actvert = CU_ACT_NONE;
+ m_curve->resolu = 2;
+
+ m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_name.c_str());
+ m_object->data = m_curve;
+}
+
+void USDCurvesReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Reading specific camera data: %s", m_prim.GetPath().GetText());
+
+ Curve *cu = (Curve *)m_object->data;
+ read_curve_sample(cu, motionSampleTime);
+
+ if (curve_prim.GetPointsAttr().ValueMightBeTimeVarying()) {
+ addCacheModifier();
+ }
+
+ USDXformReader::readObjectData(bmain, motionSampleTime);
+}
+
+void USDCurvesReader::read_curve_sample(Curve *cu, double motionSampleTime)
+{
+ curve_prim = pxr::UsdGeomBasisCurves::Get(m_stage, m_prim.GetPath());
+
+ pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr();
+ pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr();
+ pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr();
+
+ pxr::VtIntArray usdCounts;
+
+ vertexAttr.Get(&usdCounts, motionSampleTime);
+ int num_subcurves = usdCounts.size();
+
+ pxr::VtVec3fArray usdPoints;
+ pointsAttr.Get(&usdPoints, motionSampleTime);
+
+ pxr::VtFloatArray usdWidths;
+ widthsAttr.Get(&usdWidths, motionSampleTime);
+
+ pxr::UsdAttribute basisAttr = curve_prim.GetBasisAttr();
+ pxr::TfToken basis;
+ basisAttr.Get(&basis, motionSampleTime);
+
+ pxr::UsdAttribute typeAttr = curve_prim.GetTypeAttr();
+ pxr::TfToken type;
+ typeAttr.Get(&type, motionSampleTime);
+
+ pxr::UsdAttribute wrapAttr = curve_prim.GetWrapAttr();
+ pxr::TfToken wrap;
+ wrapAttr.Get(&wrap, motionSampleTime);
+
+ pxr::VtVec3fArray usdNormals;
+ curve_prim.GetNormalsAttr().Get(&usdNormals, motionSampleTime);
+
+ // If normals, extrude, else bevel
+ // Perhaps to be replaced by Blender/USD Schema
+ if (usdNormals.size() > 0) {
+ // Set extrusion to 1.0f;
+ m_curve->ext1 = 1.0f;
+ }
+ else {
+ // Set bevel depth to 1.0f;
+ m_curve->ext2 = 1.0f;
+ }
+
+ size_t idx = 0;
+ for (size_t i = 0; i < num_subcurves; i++) {
+ const int num_verts = usdCounts[i];
+ Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "usd_getnurb"));
+
+ if (basis == pxr::UsdGeomTokens->bspline) {
+ nu->flag = CU_SMOOTH;
+ nu->type = CU_NURBS;
+ }
+ else if (basis == pxr::UsdGeomTokens->bezier) {
+ // TODO: Beziers are not properly imported as beziers...
+ nu->type = CU_NURBS;
+ nu->flag |= CU_SMOOTH;
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+ else if (basis.IsEmpty()) {
+ nu->type = CU_POLY;
+ }
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+
+ nu->pntsu = num_verts;
+ nu->pntsv = 1;
+
+ if (type == pxr::UsdGeomTokens->cubic) {
+ nu->orderu = 4;
+ }
+ else if (type == pxr::UsdGeomTokens->linear) {
+ nu->orderu = 2;
+ }
+
+ if (wrap == pxr::UsdGeomTokens->periodic) {
+ nu->flagu |= CU_NURB_CYCLIC;
+ }
+ else if (wrap == pxr::UsdGeomTokens->pinned) {
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+
+ float weight = 1.0f;
+
+ nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "usd_getnurb"));
+ BPoint *bp = nu->bp;
+
+ for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
+ bp->vec[0] = (float)usdPoints[idx][0];
+ bp->vec[1] = (float)usdPoints[idx][1];
+ bp->vec[2] = (float)usdPoints[idx][2];
+ bp->vec[3] = weight;
+ bp->f1 = SELECT;
+ bp->weight = weight;
+
+ float radius = m_curve->width;
+ if (idx < usdWidths.size())
+ radius = usdWidths[idx];
+
+ bp->radius = radius;
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+ BKE_nurb_knot_calc_v(nu);
+
+ BLI_addtail(BKE_curve_nurbs_get(cu), nu);
+ }
+}
+
+Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str)
+{
+ pxr::UsdGeomCurves curve_prim = pxr::UsdGeomCurves::Get(m_stage, m_prim.GetPath());
+
+ pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr();
+ pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr();
+ pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr();
+
+ pxr::VtIntArray usdCounts;
+
+ vertexAttr.Get(&usdCounts, motionSampleTime);
+ int num_subcurves = usdCounts.size();
+
+ pxr::VtVec3fArray usdPoints;
+ pointsAttr.Get(&usdPoints, motionSampleTime);
+
+ int vertex_idx = 0;
+ int curve_idx;
+ Curve *curve = static_cast<Curve *>(m_object->data);
+
+ const int curve_count = BLI_listbase_count(&curve->nurb);
+ bool same_topology = curve_count == num_subcurves;
+
+ if (same_topology) {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
+ const int num_in_usd = usdCounts[curve_idx];
+ const int num_in_blender = nurbs->pntsu;
+
+ if (num_in_usd != num_in_blender) {
+ same_topology = false;
+ break;
+ }
+ }
+ }
+
+ if (!same_topology) {
+ BKE_nurbList_free(&curve->nurb);
+ read_curve_sample(curve, motionSampleTime);
+ }
+ else {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
+ const int totpoint = usdCounts[curve_idx];
+
+ if (nurbs->bp) {
+ BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
+ point->vec[0] = usdPoints[vertex_idx][0];
+ point->vec[1] = usdPoints[vertex_idx][1];
+ point->vec[2] = usdPoints[vertex_idx][2];
+ }
+ }
+ else if (nurbs->bezt) {
+ BezTriple *bezier = nurbs->bezt;
+
+ for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
+ bezier->vec[1][0] = usdPoints[vertex_idx][0];
+ bezier->vec[1][1] = usdPoints[vertex_idx][1];
+ bezier->vec[1][2] = usdPoints[vertex_idx][2];
+ }
+ }
+ }
+ }
+
+ return BKE_mesh_new_nomain_from_curve(m_object);
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_curve.h b/source/blender/io/usd/intern/usd_reader_curve.h
new file mode 100644
index 00000000000..1db69f91976
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_curve.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_CURVES_H__
+#define __USD_READER_CURVES_H__
+
+#include "usd.h"
+#include "usd_reader_geom.h"
+
+#include "pxr/usd/usdGeom/basisCurves.h"
+
+struct Curve;
+
+class USDCurvesReader : public USDGeomReader {
+
+ public:
+ USDCurvesReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDGeomReader(stage, object, import_params, settings)
+ {
+ }
+
+ void createObject(Main *bmain, double motionSampleTime) override;
+ void readObjectData(Main *bmain, double motionSampleTime) override;
+
+ void read_curve_sample(Curve *cu, double motionSampleTime);
+
+ Mesh *read_mesh(struct Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str) override;
+
+ protected:
+ pxr::UsdGeomBasisCurves curve_prim;
+ Curve *m_curve;
+};
+
+#endif /* __USD_READER_CURVES_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_geom.cc b/source/blender/io/usd/intern/usd_reader_geom.cc
new file mode 100644
index 00000000000..1e1acc9a773
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_geom.cc
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_geom.h"
+#include "usd_reader_prim.h"
+
+#include "MEM_guardedalloc.h"
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/base/vt/array.h>
+#include <pxr/base/vt/types.h>
+#include <pxr/base/vt/value.h>
+#include <pxr/pxr.h>
+#include <pxr/usd/sdf/assetPath.h>
+#include <pxr/usd/sdf/types.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/mesh.h>
+
+void USDGeomReader::createObject(Main *bmain, double motionSampleTime)
+{
+}
+
+bool USDGeomReader::valid() const
+{
+ return true;
+ // return m_schema.valid();
+}
+
+bool USDGeomReader::topology_changed(Mesh *existing_mesh, double motionSampleTime)
+{
+ return true;
+}
+
+void USDGeomReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+}
+
+Mesh *USDGeomReader::read_mesh(struct Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str)
+{
+ return nullptr;
+}
+
+void USDGeomReader::addCacheModifier()
+{
+ ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
+ BLI_addtail(&m_object->modifiers, md);
+
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
+
+ mcmd->cache_file = m_settings->cache_file;
+ id_us_plus(&mcmd->cache_file->id);
+ mcmd->read_flag = m_import_params.global_read_flag;
+ // mcmd->vel_fac = m_settings->vel_scale;
+
+ BLI_strncpy(mcmd->object_path, m_prim.GetPath().GetString().c_str(), FILE_MAX);
+}
+
+void USDGeomReader::addSubdivModifier()
+{
+ ModifierData *md = modifier_new(eModifierType_Subsurf);
+ BLI_addtail(&m_object->modifiers, md);
+
+ //SubsurfModifierData *subd = reinterpret_cast<SubsurfModifierData *>(md);
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_geom.h b/source/blender/io/usd/intern/usd_reader_geom.h
new file mode 100644
index 00000000000..4370b24f311
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_geom.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_GEOM_H__
+#define __USD_READER_GEOM_H__
+
+#include "usd.h"
+#include "usd_reader_xform.h"
+
+struct Mesh;
+
+class USDGeomReader : public USDXformReader {
+
+ public:
+ USDGeomReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDXformReader(stage, object, import_params, settings)
+ {
+ }
+
+ bool valid() const override;
+
+ virtual void createObject(Main *bmain, double motionSampleTime) override;
+ virtual void readObjectData(Main *bmain, double motionSampleTime) override;
+
+ virtual Mesh *read_mesh(struct Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str);
+
+ void addCacheModifier() override;
+ void addSubdivModifier();
+
+ bool topology_changed(Mesh *existing_mesh, double motionSampleTime);
+};
+
+#endif /* __USD_READER_GEOM_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_light.cc b/source/blender/io/usd/intern/usd_reader_light.cc
new file mode 100644
index 00000000000..1d947416242
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_light.cc
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_light.h"
+#include "usd_reader_prim.h"
+#include "usd_util.h"
+
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_light_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_constraint.h"
+#include "BKE_light.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/pxr.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usd/stage.h>
+
+#include <pxr/usd/usdLux/light.h>
+
+#include <pxr/usd/usdLux/diskLight.h>
+#include <pxr/usd/usdLux/distantLight.h>
+#include <pxr/usd/usdLux/rectLight.h>
+#include <pxr/usd/usdLux/shapingAPI.h>
+#include <pxr/usd/usdLux/sphereLight.h>
+
+#include <iostream>
+
+void USDLightReader::createObject(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Creating blender light for prim: %s", m_prim.GetPath().GetText());
+ Light *blight = static_cast<Light *>(BKE_light_add(bmain, m_name.c_str()));
+
+ m_object = BKE_object_add_only_object(bmain, OB_LAMP, m_name.c_str());
+ m_object->data = blight;
+}
+
+void USDLightReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ Light *blight = (Light *)m_object->data;
+
+ pxr::UsdLuxLight light_prim = pxr::UsdLuxLight::Get(m_stage, m_prim.GetPath());
+ pxr::UsdLuxShapingAPI shapingAPI(light_prim);
+
+ // Set light type
+
+ if (m_prim.IsA<pxr::UsdLuxDiskLight>()) {
+ blight->type = LA_AREA;
+ blight->area_shape = LA_AREA_DISK;
+ // Ellipse lights are not currently supported
+ }
+ else if (m_prim.IsA<pxr::UsdLuxRectLight>()) {
+ blight->type = LA_AREA;
+ blight->area_shape = LA_AREA_RECT;
+ }
+ else if (m_prim.IsA<pxr::UsdLuxSphereLight>()) {
+ blight->type = LA_LOCAL;
+
+ if (shapingAPI.GetShapingConeAngleAttr().IsAuthored()) {
+ blight->type = LA_SPOT;
+ }
+ }
+ else if (m_prim.IsA<pxr::UsdLuxDistantLight>()) {
+ blight->type = LA_SUN;
+ }
+
+ // Set light values
+
+ pxr::VtValue intensity;
+ light_prim.GetIntensityAttr().Get(&intensity, motionSampleTime);
+
+ blight->energy = intensity.Get<float>();
+
+ // TODO: Not currently supported
+ // pxr::VtValue exposure;
+ // light_prim.GetExposureAttr().Get(&exposure, motionSampleTime);
+
+ // TODO: Not currently supported
+ // pxr::VtValue diffuse;
+ // light_prim.GetDiffuseAttr().Get(&diffuse, motionSampleTime);
+
+ pxr::VtValue specular;
+ light_prim.GetSpecularAttr().Get(&specular, motionSampleTime);
+ blight->spec_fac = specular.Get<float>();
+
+ pxr::VtValue color;
+ light_prim.GetColorAttr().Get(&color, motionSampleTime);
+ pxr::GfVec3f color_vec = color.Get<pxr::GfVec3f>();
+ blight->r = color_vec[0];
+ blight->g = color_vec[1];
+ blight->b = color_vec[2];
+
+ // TODO: Not currently supported
+ // pxr::VtValue use_color_temp;
+ // light_prim.GetEnableColorTemperatureAttr().Get(&use_color_temp, motionSampleTime);
+
+ // TODO: Not currently supported
+ // pxr::VtValue color_temp;
+ // light_prim.GetColorTemperatureAttr().Get(&color_temp, motionSampleTime);
+
+ switch (blight->type) {
+ case LA_AREA:
+ if (blight->area_shape == LA_AREA_RECT && m_prim.IsA<pxr::UsdLuxRectLight>()) {
+ pxr::UsdLuxRectLight rect_light = pxr::UsdLuxRectLight::Get(m_stage, m_prim.GetPath());
+
+ pxr::VtValue width;
+ rect_light.GetWidthAttr().Get(&width, motionSampleTime);
+
+ pxr::VtValue height;
+ rect_light.GetHeightAttr().Get(&height, motionSampleTime);
+
+ blight->area_size = width.Get<float>();
+ blight->area_sizey = height.Get<float>();
+ }
+
+ if (blight->area_shape == LA_AREA_DISK && m_prim.IsA<pxr::UsdLuxDiskLight>()) {
+ pxr::UsdLuxDiskLight disk_light = pxr::UsdLuxDiskLight::Get(m_stage, m_prim.GetPath());
+
+ pxr::VtValue radius;
+ disk_light.GetRadiusAttr().Get(&radius, motionSampleTime);
+
+ blight->area_size = radius.Get<float>() * 2.0f;
+ }
+ break;
+ case LA_LOCAL:
+ if (m_prim.IsA<pxr::UsdLuxSphereLight>()) {
+ pxr::UsdLuxSphereLight sphere_light = pxr::UsdLuxSphereLight::Get(m_stage,
+ m_prim.GetPath());
+
+ pxr::VtValue radius;
+ sphere_light.GetRadiusAttr().Get(&radius, motionSampleTime);
+
+ blight->area_size = radius.Get<float>();
+ }
+ break;
+ case LA_SPOT:
+ if (m_prim.IsA<pxr::UsdLuxSphereLight>()) {
+ pxr::UsdLuxSphereLight sphere_light = pxr::UsdLuxSphereLight::Get(m_stage,
+ m_prim.GetPath());
+
+ pxr::VtValue radius;
+ sphere_light.GetRadiusAttr().Get(&radius, motionSampleTime);
+
+ blight->area_size = radius.Get<float>();
+
+ pxr::VtValue coneAngle;
+ shapingAPI.GetShapingConeAngleAttr().Get(&coneAngle, motionSampleTime);
+ blight->spotsize = coneAngle.Get<float>() * ((float)M_PI / 180.0f) * 2.0f;
+
+ pxr::VtValue spotBlend;
+ shapingAPI.GetShapingConeSoftnessAttr().Get(&spotBlend, motionSampleTime);
+ blight->spotblend = spotBlend.Get<float>();
+ }
+ break;
+ case LA_SUN:
+ if (m_prim.IsA<pxr::UsdLuxDistantLight>()) {
+ pxr::UsdLuxDistantLight distant_light = pxr::UsdLuxDistantLight::Get(m_stage,
+ m_prim.GetPath());
+
+ pxr::VtValue angle;
+ distant_light.GetAngleAttr().Get(&angle, motionSampleTime);
+ blight->sun_angle = angle.Get<float>();
+ }
+ break;
+ }
+
+ USDXformReader::readObjectData(bmain, motionSampleTime);
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_light.h b/source/blender/io/usd/intern/usd_reader_light.h
new file mode 100644
index 00000000000..bc8b4301ead
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_light.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_LIGHT_H__
+#define __USD_READER_LIGHT_H__
+
+#include "usd.h"
+#include "usd_reader_xform.h"
+
+class USDLightReader : public USDXformReader {
+
+ public:
+ USDLightReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDXformReader(stage, object, import_params, settings)
+ {
+ }
+
+ void createObject(Main *bmain, double motionSampleTime) override;
+ void readObjectData(Main *bmain, double motionSampleTime) override;
+};
+
+#endif /* __USD_READER_LIGHT_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
new file mode 100644
index 00000000000..a4a2c474a99
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -0,0 +1,740 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_mesh.h"
+#include "usd_reader_prim.h"
+
+#include "MEM_guardedalloc.h"
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/base/vt/array.h>
+#include <pxr/base/vt/types.h>
+#include <pxr/base/vt/value.h>
+#include <pxr/pxr.h>
+#include <pxr/usd/sdf/assetPath.h>
+#include <pxr/usd/sdf/types.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/mesh.h>
+#include <pxr/usd/usdGeom/subset.h>
+#include <pxr/usd/usdShade/materialBindingAPI.h>
+
+#include <iostream>
+
+namespace usdtokens {
+// Materials
+static const pxr::TfToken st("st", pxr::TfToken::Immortal);
+static const pxr::TfToken UVMap("UVMap", pxr::TfToken::Immortal);
+static const pxr::TfToken Cd("Cd", pxr::TfToken::Immortal);
+static const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal);
+} // namespace usdtokens
+
+namespace utils {
+// Very similar to abc mesh utils
+static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map)
+{
+ Material *material = static_cast<Material *>(bmain->materials.first);
+
+ for (; material; material = static_cast<Material *>(material->id.next)) {
+ // We have to do this because the stored material name is coming directly from usd
+ mat_map[pxr::TfMakeValidIdentifier(material->id.name + 2).c_str()] = material;
+ }
+}
+
+static void assign_materials(Main *bmain,
+ Object *ob,
+ const std::map<std::string, int> &mat_index_map)
+{
+ bool can_assign = true;
+ std::map<std::string, int>::const_iterator it = mat_index_map.begin();
+
+ int matcount = 0;
+ for (; it != mat_index_map.end(); ++it, matcount++) {
+ if (!BKE_object_material_slot_add(bmain, ob)) {
+ can_assign = false;
+ break;
+ }
+ }
+
+ /* TODO(kevin): use global map? */
+ std::map<std::string, Material *> mat_map;
+ build_mat_map(bmain, mat_map);
+
+ std::map<std::string, Material *>::iterator mat_iter;
+
+ if (can_assign) {
+ it = mat_index_map.begin();
+
+ for (; it != mat_index_map.end(); ++it) {
+ std::string mat_name = it->first;
+ mat_iter = mat_map.find(mat_name.c_str());
+
+ Material *assigned_mat;
+
+ if (mat_iter == mat_map.end()) {
+ assigned_mat = BKE_material_add(bmain, mat_name.c_str());
+ mat_map[mat_name] = assigned_mat;
+ }
+ else {
+ assigned_mat = mat_iter->second;
+ }
+
+ BKE_object_material_assign(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA);
+ }
+ }
+}
+
+} // namespace utils
+
+static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
+{
+ CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ void *cd_ptr;
+ CustomData *loopdata;
+ int numloops;
+
+ /* unsupported custom data type -- don't do anything. */
+ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ return NULL;
+ }
+
+ loopdata = &mesh->ldata;
+ cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
+ if (cd_ptr != NULL) {
+ /* layer already exists, so just return it. */
+ return cd_ptr;
+ }
+
+ /* Create a new layer. */
+ numloops = mesh->totloop;
+ cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, NULL, numloops, name);
+ return cd_ptr;
+}
+
+USDMeshReader::USDMeshReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDGeomReader(stage, object, import_params, settings),
+ m_lastNumPositions(-1),
+ m_hasUVs(false),
+ m_isTimeVarying(false),
+ m_isInitialLoad(false)
+{
+}
+
+void USDMeshReader::createObject(Main *bmain, double motionSampleTime)
+{
+ Mesh *mesh = BKE_mesh_add(bmain, m_name.c_str());
+
+ m_object = BKE_object_add_only_object(bmain, OB_MESH, m_name.c_str());
+ m_object->data = mesh;
+
+ /*
+ if (m_settings->validate_meshes) {
+ BKE_mesh_validate(mesh, false, false);
+ }
+
+ readFaceSetsSample(bmain, mesh, sample_sel);
+ */
+}
+
+void USDMeshReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Reading specific mesh data: %s", m_prim.GetPath().GetText());
+
+ Mesh *mesh = (Mesh *)m_object->data;
+
+ m_isInitialLoad = true;
+ Mesh *read_mesh = this->read_mesh(
+ mesh, motionSampleTime, m_import_params.global_read_flag, 1.0f, NULL);
+ m_isInitialLoad = false;
+ if (read_mesh != mesh) {
+ /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_nomain_to_mesh() */
+ /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
+ short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true);
+ mesh->flag |= autosmooth;
+ }
+
+ readFaceSetsSample(bmain, mesh, motionSampleTime);
+
+ if (mesh_prim.GetPointsAttr().ValueMightBeTimeVarying())
+ m_isTimeVarying = true;
+
+ if (m_isTimeVarying) {
+ addCacheModifier();
+ }
+
+ if (m_import_params.import_subdiv) {
+ pxr::TfToken subdivScheme;
+ mesh_prim.GetSubdivisionSchemeAttr().Get(&subdivScheme, motionSampleTime);
+
+ if (subdivScheme == pxr::UsdGeomTokens->catmullClark) {
+ addSubdivModifier();
+ }
+ }
+
+ USDXformReader::readObjectData(bmain, motionSampleTime);
+}
+
+bool USDMeshReader::valid() const
+{
+ return mesh_prim.GetPrim().IsValid();
+}
+
+bool USDMeshReader::topology_changed(Mesh *existing_mesh, double motionSampleTime)
+{
+ pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr();
+ pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr();
+ pxr::UsdAttribute pointsAttr = mesh_prim.GetPointsAttr();
+ pxr::UsdAttribute normalsAttr = mesh_prim.GetNormalsAttr();
+
+ faceVertIndicesAttr.Get(&m_face_indices, motionSampleTime);
+ faceVertCountsAttr.Get(&m_face_counts, motionSampleTime);
+ pointsAttr.Get(&m_positions, motionSampleTime);
+
+ normalsAttr.Get(&m_normals, motionSampleTime);
+
+ if (m_lastNumPositions != m_positions.size()) {
+ m_lastNumPositions = m_positions.size();
+ return true;
+ }
+
+ return false;
+}
+
+void USDMeshReader::read_mpolys(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, double motionSampleTime)
+{
+ MPoly *mpolys = mesh->mpoly;
+ MLoop *mloops = mesh->mloop;
+
+ pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr();
+ pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr();
+
+ pxr::VtIntArray face_counts;
+ faceVertCountsAttr.Get(&face_counts, motionSampleTime);
+ pxr::VtIntArray face_indices;
+ faceVertIndicesAttr.Get(&face_indices, motionSampleTime);
+
+ unsigned int loop_index = 0;
+ unsigned int rev_loop_index = 0;
+
+ for (int i = 0; i < face_counts.size(); i++) {
+ const int face_size = face_counts[i];
+
+ MPoly &poly = mpolys[i];
+ poly.loopstart = loop_index;
+ poly.totloop = face_size;
+ poly.mat_nr = 0;
+
+ /* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded,
+ * this is encoded in custom loop normals. See T71246. */
+ poly.flag |= ME_SMOOTH;
+
+ rev_loop_index = loop_index + (face_size - 1);
+
+ for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
+ MLoop &loop = mloops[loop_index];
+ if (m_isLeftHanded)
+ loop.v = face_indices[rev_loop_index];
+ else
+ loop.v = face_indices[loop_index];
+ }
+ }
+
+ BKE_mesh_calc_edges(mesh, false, false);
+}
+
+void USDMeshReader::read_uvs(Mesh *mesh,
+ pxr::UsdGeomMesh mesh_prim,
+ double motionSampleTime,
+ bool load_uvs)
+{
+ unsigned int loop_index = 0;
+ unsigned int rev_loop_index = 0;
+ unsigned int uv_index = 0;
+
+ const CustomData *ldata = &mesh->ldata;
+ std::vector<pxr::VtVec2fArray> uv_primvars;
+ uv_primvars.resize(ldata->totlayer);
+
+ if (m_hasUVs) {
+ for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) {
+ const CustomDataLayer *layer = &ldata->layers[layer_idx];
+ std::string layer_name = std::string(layer->name);
+ if (layer->type != CD_MLOOPUV) {
+ continue;
+ }
+ pxr::VtVec2fArray uvs;
+
+ pxr::TfToken uv_token;
+
+ // If first time seeing uv token, store in map of <layer->uid, TfToken>
+ if (uv_token_map.find(layer_name) == uv_token_map.end()) {
+ uv_token = pxr::TfToken(layer_name);
+ uv_token_map.insert(std::make_pair(layer_name, uv_token));
+ }
+ else
+ uv_token = uv_token_map.at(layer_name);
+
+ // Early out if no token found, this should never happen
+ if (uv_token.IsEmpty()) {
+ continue;
+ }
+ // Early out if not first load and uvs arent animated
+ if (!load_uvs && primvar_varying_map.find(uv_token) != primvar_varying_map.end() &&
+ !primvar_varying_map.at(uv_token)) {
+ continue;
+ }
+
+ // Early out if mesh doesn't have primvar
+ if (!mesh_prim.HasPrimvar(uv_token)) {
+ continue;
+ }
+
+ mesh_prim.GetPrimvar(uv_token).Get<pxr::VtVec2fArray>(&uvs, motionSampleTime);
+
+ uv_primvars[layer_idx] = uvs;
+ }
+ }
+
+ for (int i = 0; i < m_face_counts.size(); i++) {
+ const int face_size = m_face_counts[i];
+
+ rev_loop_index = loop_index + (face_size - 1);
+
+ for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
+
+ for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) {
+ const CustomDataLayer *layer = &ldata->layers[layer_idx];
+ if (layer->type != CD_MLOOPUV) {
+ continue;
+ }
+
+ // Early out if mismatched layer sizes
+ if (layer_idx > uv_primvars.size()) {
+ continue;
+ }
+
+ // Early out if no uvs loaded
+ if (uv_primvars[layer_idx].empty()) {
+ continue;
+ }
+
+ pxr::VtVec2fArray &uvs = uv_primvars[layer_idx];
+
+ MLoopUV *mloopuv = static_cast<MLoopUV *>(layer->data);
+ if (m_isLeftHanded)
+ uv_index = loop_index;
+ else
+ uv_index = rev_loop_index;
+
+ if (uv_index >= uvs.size()) {
+ continue;
+ }
+ mloopuv[uv_index].uv[0] = uvs[uv_index][0];
+ mloopuv[uv_index].uv[1] = uvs[uv_index][1];
+ }
+ }
+ }
+ BKE_mesh_calc_edges(mesh, false, false);
+}
+
+void USDMeshReader::read_attributes(Mesh *mesh,
+ pxr::UsdGeomMesh mesh_prim,
+ double motionSampleTime)
+{
+ CustomData *cd = &mesh->vdata;
+ std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim.GetPrimvars();
+
+ for (pxr::UsdGeomPrimvar p : primvars) {
+ int cd_type = 0;
+ size_t num = 0;
+ size_t type_size = 0;
+ void *data;
+
+ if (!p.HasAuthoredValue())
+ continue;
+
+ if (!m_isInitialLoad &&
+ primvar_varying_map.find(p.GetPrimvarName()) == primvar_varying_map.end())
+ continue;
+
+ const char *name = p.GetPrimvarName().GetString().c_str();
+ if (p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2hArray ||
+ p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2fArray ||
+ p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2dArray) {
+ continue;
+ }
+ else if (p.GetTypeName() == pxr::SdfValueTypeNames->Color3fArray ||
+ p.GetTypeName() == pxr::SdfValueTypeNames->Double3Array ||
+ p.GetTypeName() == pxr::SdfValueTypeNames->Float3Array) {
+ cd_type = CD_VALUE_F3;
+ pxr::VtVec3fArray idata;
+ p.Get<pxr::VtVec3fArray>(&idata, motionSampleTime);
+ num = idata.size();
+ type_size = sizeof(pxr::GfVec3f);
+ data = (void *)idata.cdata();
+ }
+ else if (p.GetTypeName() == pxr::SdfValueTypeNames->FloatArray ||
+ p.GetTypeName() == pxr::SdfValueTypeNames->DoubleArray) {
+ cd_type = CD_VALUE_FLOAT;
+ pxr::VtFloatArray idata;
+ p.Get<pxr::VtFloatArray>(&idata, motionSampleTime);
+ num = idata.size();
+ type_size = sizeof(float);
+ data = (void *)idata.cdata();
+ }
+ else if (p.GetTypeName() == pxr::SdfValueTypeNames->IntArray) {
+ cd_type = CD_VALUE_INT;
+ pxr::VtIntArray idata;
+ p.Get<pxr::VtIntArray>(&idata, motionSampleTime);
+ num = idata.size();
+ type_size = sizeof(int);
+ data = (void *)idata.cdata();
+ }
+ else if (p.GetTypeName() == pxr::SdfValueTypeNames->Int3Array) {
+ cd_type = CD_VALUE_I3;
+ pxr::VtVec3iArray idata;
+ p.Get<pxr::VtVec3iArray>(&idata, motionSampleTime);
+ num = idata.size();
+ type_size = sizeof(pxr::GfVec3i);
+ data = (void *)idata.cdata();
+ }
+
+ void *cdata = CustomData_get_layer_named(cd, cd_type, name);
+
+ if (!cdata) {
+ cdata = CustomData_add_layer_named(cd, cd_type, CD_DEFAULT, NULL, num, name);
+ }
+ memcpy(cdata, data, num * type_size);
+ }
+}
+
+void USDMeshReader::read_vels(Mesh *mesh,
+ pxr::UsdGeomMesh mesh_prim,
+ float vel_scale,
+ double motionSampleTime)
+{
+ pxr::VtVec3fArray velocities;
+ pxr::UsdAttribute vel_attr = mesh_prim.GetVelocitiesAttr();
+
+ if (!m_isInitialLoad && !vel_attr.ValueMightBeTimeVarying())
+ return;
+
+ vel_attr.Get<pxr::VtVec3fArray>(&velocities, motionSampleTime);
+
+ if (velocities.size() <= 0)
+ return;
+
+ float(*vdata)[3] = (float(*)[3])CustomData_add_layer(
+ &mesh->vdata, CD_VELOCITY, CD_DEFAULT, NULL, mesh->totvert);
+
+ if (vdata) {
+ for (int i = 0; i < mesh->totvert; i++) {
+ vdata[i][0] = velocities[i][0] * vel_scale;
+ vdata[i][1] = velocities[i][1] * vel_scale;
+ vdata[i][2] = velocities[i][2] * vel_scale;
+ }
+ }
+}
+
+void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
+{
+ for (int i = 0; i < m_normals.size(); i++) {
+ MVert &mvert = mesh->mvert[i];
+ mvert.no[0] = m_normals[i][0];
+ mvert.no[1] = m_normals[i][1];
+ mvert.no[2] = m_normals[i][2];
+ }
+}
+
+void USDMeshReader::process_normals_face_varying(Mesh *mesh)
+{
+ if (m_normals.size() <= 0) {
+ BKE_mesh_calc_normals(mesh);
+ return;
+ }
+
+ // mesh->flag |= ME_AUTOSMOOTH;
+
+ long int loop_count = m_normals.size();
+
+ float(*lnors)[3] = static_cast<float(*)[3]>(
+ MEM_malloc_arrayN(loop_count, sizeof(float[3]), "USD::FaceNormals"));
+
+ MPoly *mpoly = mesh->mpoly;
+ int usd_index = 0;
+
+ for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mpoly) {
+ for (int j = 0; j < mpoly->totloop; j++, usd_index++) {
+ int blender_index = mpoly->loopstart + j;
+
+ lnors[blender_index][0] = m_normals[usd_index][0];
+ lnors[blender_index][1] = m_normals[usd_index][1];
+ lnors[blender_index][2] = m_normals[usd_index][2];
+ }
+ }
+ BKE_mesh_set_custom_normals(mesh, lnors);
+
+ MEM_freeN(lnors);
+}
+
+void USDMeshReader::read_mesh_sample(const std::string &iobject_full_name,
+ ImportSettings *settings,
+ Mesh *mesh,
+ const pxr::UsdGeomMesh &mesh_prim,
+ double motionSampleTime,
+ bool new_mesh)
+{
+
+ pxr::UsdAttribute normalsAttr = mesh_prim.GetNormalsAttr();
+ /*pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr();
+ pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr();*/
+
+ std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim.GetPrimvars();
+ /*pxr::UsdAttribute pointsAttr = mesh_prim.GetPointsAttr();*/
+ pxr::UsdAttribute subdivSchemeAttr = mesh_prim.GetSubdivisionSchemeAttr();
+
+ /*pxr::VtIntArray face_indices;
+ faceVertIndicesAttr.Get(&face_indices, motionSampleTime);
+ pxr::VtIntArray face_counts;
+ faceVertIndicesAttr.Get(&face_counts, motionSampleTime);
+ pxr::VtVec3fArray positions;
+ pointsAttr.Get(&positions, motionSampleTime);*/
+
+ /*get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
+
+ if (config.weight != 0.0f) {
+ Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample;
+ schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
+ abc_mesh_data.ceil_positions = ceil_sample.getPositions();
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
+ }*/
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
+ for (int i = 0; i < m_positions.size(); i++) {
+ MVert &mvert = mesh->mvert[i];
+ mvert.co[0] = m_positions[i][0];
+ mvert.co[1] = m_positions[i][1];
+ mvert.co[2] = m_positions[i][2];
+ }
+
+ if (m_normalInterpolation == pxr::UsdGeomTokens->vertex)
+ process_normals_vertex_varying(mesh);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+ read_mpolys(mesh, mesh_prim, motionSampleTime);
+ if (m_normalInterpolation == pxr::UsdGeomTokens->faceVarying)
+ process_normals_face_varying(mesh);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs(mesh, mesh_prim, motionSampleTime, new_mesh);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_ATTR) != 0) {
+ read_attributes(mesh, mesh_prim, motionSampleTime);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VELS) != 0) {
+ read_vels(mesh, mesh_prim, settings->vel_scale, motionSampleTime);
+ }
+}
+
+void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
+ MPoly *mpoly,
+ int totpoly,
+ std::map<std::string, int> &r_mat_map)
+{
+ pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(m_prim);
+ std::vector<pxr::UsdGeomSubset> subsets = api.GetMaterialBindSubsets();
+
+ int current_mat = 0;
+ if (subsets.size() > 0) {
+ for (pxr::UsdGeomSubset &subset : subsets) {
+ pxr::UsdShadeMaterialBindingAPI subsetAPI = pxr::UsdShadeMaterialBindingAPI(
+ subset.GetPrim());
+ std::string materialName = subsetAPI.GetDirectBinding().GetMaterialPath().GetName();
+
+ if (r_mat_map.find(materialName) == r_mat_map.end()) {
+ r_mat_map[materialName] = 1 + current_mat++;
+ }
+
+ const int mat_idx = r_mat_map[materialName] - 1;
+
+ pxr::UsdAttribute indicesAttribute = subset.GetIndicesAttr();
+ pxr::VtIntArray indices;
+ indicesAttribute.Get(&indices, motionSampleTime);
+
+ for (int i = 0; i < indices.size(); i++) {
+ MPoly &poly = mpoly[indices[i]];
+ poly.mat_nr = mat_idx;
+ }
+ }
+ }
+ else {
+ r_mat_map[api.GetDirectBinding().GetMaterialPath().GetName()] = 1;
+ }
+}
+
+void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double motionSampleTime)
+{
+ std::map<std::string, int> mat_map;
+ assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, mat_map);
+ utils::assign_materials(bmain, m_object, mat_map);
+}
+
+Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str)
+{
+ mesh_prim = pxr::UsdGeomMesh::Get(m_stage, m_prim.GetPath());
+
+ // pxr::UsdAttribute normalsAttr = mesh_prim.GetNormalsAttr();
+ // pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr();
+ // pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr();
+
+ m_normalInterpolation = mesh_prim.GetNormalsInterpolation();
+
+ mesh_prim.GetOrientationAttr().Get(&m_orientation);
+ if (m_orientation == pxr::UsdGeomTokens->leftHanded)
+ m_isLeftHanded = true;
+
+ std::vector<pxr::TfToken> uv_tokens;
+
+ std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim.GetPrimvars();
+
+ for (pxr::UsdGeomPrimvar p : primvars) {
+ if (primvar_varying_map.find(p.GetPrimvarName()) == primvar_varying_map.end()) {
+ primvar_varying_map.insert(std::make_pair(p.GetPrimvarName(), p.ValueMightBeTimeVarying()));
+ if (p.ValueMightBeTimeVarying())
+ m_isTimeVarying = true;
+ }
+
+ // Assume all uvs are stored in one of these primvar types...
+ if (p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2hArray ||
+ p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2fArray ||
+ p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2dArray) {
+ uv_tokens.push_back(p.GetBaseName());
+ m_hasUVs = true;
+ }
+ }
+
+ // pxr::UsdAttribute pointsAttr = mesh_prim.GetPointsAttr();
+ // pxr::UsdAttribute subdivSchemeAttr = mesh_prim.GetSubdivisionSchemeAttr();
+
+ // pxr::VtIntArray face_indices;
+ // faceVertIndicesAttr.Get(&face_indices, motionSampleTime);
+ // pxr::VtIntArray face_counts;
+ // faceVertCountsAttr.Get(&face_counts, motionSampleTime);
+ // pxr::VtVec3fArray positions;
+ // pointsAttr.Get(&positions, motionSampleTime);
+
+ Mesh *active_mesh = existing_mesh;
+ bool new_mesh = false;
+
+ /* Only read point data when streaming meshes, unless we need to create new ones. */
+ ImportSettings settings;
+ settings.read_flag |= read_flag;
+ settings.vel_scale = vel_scale;
+
+ if (topology_changed(existing_mesh, motionSampleTime)) {
+ new_mesh = true;
+ active_mesh = BKE_mesh_new_nomain_from_template(
+ existing_mesh, m_positions.size(), 0, 0, m_face_indices.size(), m_face_counts.size());
+
+ for (pxr::TfToken token : uv_tokens) {
+ void *cd_ptr = add_customdata_cb(active_mesh, token.GetText(), CD_MLOOPUV);
+ active_mesh->mloopuv = static_cast<MLoopUV *>(cd_ptr);
+ }
+
+ // settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ }
+ // else {
+ /* If the face count changed (e.g. by triangulation), only read points.
+ * This prevents crash from T49813.
+ * TODO(kevin): perhaps find a better way to do this? */
+ /*if (face_counts.size() != existing_mesh->totpoly ||
+ face_indices.size() != existing_mesh->totloop) {
+ //settings.read_flag = MOD_MESHSEQ_READ_VERT;
+ std::cout << "Mismatch vert counts\n";
+ if (err_str) {
+ *err_str =
+ "Topology has changed, perhaps by triangulating the"
+ " mesh. Only vertices will be read!";
+ }
+ }
+}*/
+
+ read_mesh_sample(m_prim.GetPath().GetString().c_str(),
+ &settings,
+ active_mesh,
+ mesh_prim,
+ motionSampleTime,
+ new_mesh || m_isInitialLoad);
+
+ if (new_mesh) {
+ /* Here we assume that the number of materials doesn't change, i.e. that
+ * the material slots that were created when the object was loaded from
+ * USD are still valid now. */
+ size_t num_polys = active_mesh->totpoly;
+ if (num_polys > 0) {
+ std::map<std::string, int> mat_map;
+ assign_facesets_to_mpoly(motionSampleTime, active_mesh->mpoly, num_polys, mat_map);
+ }
+ }
+
+ return active_mesh;
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
new file mode 100644
index 00000000000..e4933c018ad
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_MESH_H__
+#define __USD_READER_MESH_H__
+
+#include "pxr/usd/usdGeom/mesh.h"
+#include "usd.h"
+#include "usd_reader_geom.h"
+
+typedef float f3Data[3];
+
+class USDMeshReader : public USDGeomReader {
+
+ public:
+ USDMeshReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings);
+
+ bool valid() const override;
+
+ void createObject(Main *bmain, double motionSampleTime) override;
+ void readObjectData(Main *bmain, double motionSampleTime) override;
+
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str);
+ bool topology_changed(Mesh *existing_mesh, double motionSampleTime);
+
+ private:
+ void process_normals_vertex_varying(Mesh *mesh);
+ void process_normals_face_varying(Mesh *mesh);
+ void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime);
+ void assign_facesets_to_mpoly(double motionSampleTime,
+ struct MPoly *mpoly,
+ int totpoly,
+ std::map<std::string, int> &r_mat_map);
+
+ void read_mpolys(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, double motionSampleTime);
+ void read_uvs(Mesh *mesh,
+ pxr::UsdGeomMesh mesh_prim,
+ double motionSampleTime,
+ bool load_uvs = false);
+ void read_attributes(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, double motionSampleTime);
+ void read_vels(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, float vel_scale, double motionSampleTime);
+
+ void read_mesh_sample(const std::string &iobject_full_name,
+ ImportSettings *settings,
+ Mesh *mesh,
+ const pxr::UsdGeomMesh &mesh_prim,
+ double motionSampleTime,
+ bool new_mesh);
+
+ pxr::UsdGeomMesh mesh_prim;
+
+ std::unordered_map<std::string, pxr::TfToken> uv_token_map;
+ std::map<const pxr::TfToken, bool> primvar_varying_map;
+
+ pxr::VtIntArray m_face_indices;
+ pxr::VtIntArray m_face_counts;
+ pxr::VtVec3fArray m_positions;
+ pxr::VtVec3fArray m_normals;
+ pxr::TfToken m_normalInterpolation;
+ pxr::TfToken m_orientation;
+ bool m_isLeftHanded;
+
+ int m_lastNumPositions;
+
+ bool m_hasUVs;
+ bool m_isTimeVarying;
+
+ // This is to ensure we load all data once because we reuse the read_mesh function
+ // in the mesh seq modifier, and in initial load. Ideally a better fix would be
+ // implemented. Note this will break if face or positions vary...
+ bool m_isInitialLoad;
+};
+
+#endif /* __USD_READER_MESH_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.cc b/source/blender/io/usd/intern/usd_reader_nurbs.cc
new file mode 100644
index 00000000000..7d6693b78a4
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_nurbs.cc
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_nurbs.h"
+#include "usd_reader_prim.h"
+
+#include "MEM_guardedalloc.h"
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/base/vt/array.h>
+#include <pxr/base/vt/types.h>
+#include <pxr/base/vt/value.h>
+#include <pxr/pxr.h>
+#include <pxr/usd/sdf/assetPath.h>
+#include <pxr/usd/sdf/types.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/basisCurves.h>
+#include <pxr/usd/usdGeom/curves.h>
+
+static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots)
+{
+ if (knots.size() == 0) {
+ return false;
+ }
+
+ /* Skip first and last knots, as they are used for padding. */
+ const size_t num_knots = knots.size();
+ nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "usd_setsplineknotsu"));
+
+ for (size_t i = 0; i < num_knots; i++) {
+ nu_knots[i] = (float)knots[i];
+ }
+
+ return true;
+}
+
+void USDNurbsReader::createObject(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Creating blender curve for prim: %s", m_prim.GetPath().GetText());
+ m_curve = BKE_curve_add(bmain, m_name.c_str(), OB_CURVE);
+
+ m_curve->flag |= CU_DEFORM_FILL | CU_3D;
+ m_curve->actvert = CU_ACT_NONE;
+ m_curve->resolu = 2;
+
+ m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_name.c_str());
+ m_object->data = m_curve;
+}
+
+void USDNurbsReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Reading specific camera data: %s", m_prim.GetPath().GetText());
+
+ Curve *cu = (Curve *)m_object->data;
+ read_curve_sample(cu, motionSampleTime);
+
+ if (curve_prim.GetPointsAttr().ValueMightBeTimeVarying()) {
+ addCacheModifier();
+ }
+
+ USDXformReader::readObjectData(bmain, motionSampleTime);
+}
+
+void USDNurbsReader::read_curve_sample(Curve *cu, double motionSampleTime)
+{
+ curve_prim = pxr::UsdGeomNurbsCurves::Get(m_stage, m_prim.GetPath());
+
+ pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr();
+ pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr();
+ pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr();
+
+ pxr::VtIntArray usdCounts;
+
+ vertexAttr.Get(&usdCounts, motionSampleTime);
+ int num_subcurves = usdCounts.size();
+
+ pxr::VtVec3fArray usdPoints;
+ pointsAttr.Get(&usdPoints, motionSampleTime);
+
+ pxr::VtFloatArray usdWidths;
+ widthsAttr.Get(&usdWidths, motionSampleTime);
+
+ pxr::VtIntArray orders;
+ curve_prim.GetOrderAttr().Get(&orders, motionSampleTime);
+
+ pxr::VtDoubleArray knots;
+ curve_prim.GetKnotsAttr().Get(&knots, motionSampleTime);
+
+ pxr::VtVec3fArray usdNormals;
+ curve_prim.GetNormalsAttr().Get(&usdNormals, motionSampleTime);
+
+ // If normals, extrude, else bevel
+ // Perhaps to be replaced by Blender/USD Schema
+ if (usdNormals.size() > 0) {
+ // Set extrusion to 1.0f;
+ m_curve->ext1 = 1.0f;
+ }
+ else {
+ // Set bevel depth to 1.0f;
+ m_curve->ext2 = 1.0f;
+ }
+
+ size_t idx = 0;
+ for (size_t i = 0; i < num_subcurves; i++) {
+ const int num_verts = usdCounts[i];
+
+ Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "usd_getnurb"));
+ nu->flag = CU_SMOOTH;
+ nu->type = CU_NURBS;
+
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+
+ nu->pntsu = num_verts;
+ nu->pntsv = 1;
+
+ if (i < orders.size()) {
+ nu->orderu = static_cast<short>(orders[i]);
+ }
+ else {
+ nu->orderu = 4;
+ nu->orderv = 4;
+ }
+
+ // TODO: Not needed at present, left for future dev
+ // if (knots.size() > 3) {
+ // if ((knots[0] == knots[1]) && (knots[knots.size()] == knots[knots.size() - 1])) {
+ // nu->flagu |= CU_NURB_ENDPOINT;
+ // } else {
+ // nu->flagu |= CU_NURB_CYCLIC;
+ // }
+ // }
+
+ float weight = 1.0f;
+
+ nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "usd_getnurb"));
+ BPoint *bp = nu->bp;
+
+ for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
+ bp->vec[0] = (float)usdPoints[idx][0];
+ bp->vec[1] = (float)usdPoints[idx][1];
+ bp->vec[2] = (float)usdPoints[idx][2];
+ bp->vec[3] = weight;
+ bp->f1 = SELECT;
+ bp->weight = weight;
+
+ float radius = 0.1f;
+ if (idx < usdWidths.size())
+ radius = usdWidths[idx];
+
+ bp->radius = radius;
+ }
+
+ if (!set_knots(knots, nu->knotsu)) {
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ BLI_addtail(BKE_curve_nurbs_get(cu), nu);
+ }
+}
+
+Mesh *USDNurbsReader::read_mesh(struct Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str)
+{
+ pxr::UsdGeomCurves curve_prim = pxr::UsdGeomCurves::Get(m_stage, m_prim.GetPath());
+
+ pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr();
+ pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr();
+ pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr();
+
+ pxr::VtIntArray usdCounts;
+
+ vertexAttr.Get(&usdCounts, motionSampleTime);
+ int num_subcurves = usdCounts.size();
+
+ pxr::VtVec3fArray usdPoints;
+ pointsAttr.Get(&usdPoints, motionSampleTime);
+
+ int vertex_idx = 0;
+ int curve_idx;
+ Curve *curve = static_cast<Curve *>(m_object->data);
+
+ const int curve_count = BLI_listbase_count(&curve->nurb);
+ bool same_topology = curve_count == num_subcurves;
+
+ if (same_topology) {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
+ const int num_in_usd = usdCounts[curve_idx];
+ const int num_in_blender = nurbs->pntsu;
+
+ if (num_in_usd != num_in_blender) {
+ same_topology = false;
+ break;
+ }
+ }
+ }
+
+ if (!same_topology) {
+ BKE_nurbList_free(&curve->nurb);
+ read_curve_sample(curve, motionSampleTime);
+ }
+ else {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
+ const int totpoint = usdCounts[curve_idx];
+
+ if (nurbs->bp) {
+ BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
+ point->vec[0] = usdPoints[vertex_idx][0];
+ point->vec[1] = usdPoints[vertex_idx][1];
+ point->vec[2] = usdPoints[vertex_idx][2];
+ }
+ }
+ else if (nurbs->bezt) {
+ BezTriple *bezier = nurbs->bezt;
+
+ for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
+ bezier->vec[1][0] = usdPoints[vertex_idx][0];
+ bezier->vec[1][1] = usdPoints[vertex_idx][1];
+ bezier->vec[1][2] = usdPoints[vertex_idx][2];
+ }
+ }
+ }
+ }
+
+ return BKE_mesh_new_nomain_from_curve(m_object);
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.h b/source/blender/io/usd/intern/usd_reader_nurbs.h
new file mode 100644
index 00000000000..4849c02c38c
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_nurbs.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_NURBS_H__
+#define __USD_READER_NURBS_H__
+
+#include "usd.h"
+#include "usd_reader_geom.h"
+
+#include "pxr/usd/usdGeom/nurbsCurves.h"
+
+struct Curve;
+
+class USDNurbsReader : public USDGeomReader {
+
+ public:
+ USDNurbsReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDGeomReader(stage, object, import_params, settings)
+ {
+ }
+
+ void createObject(Main *bmain, double motionSampleTime) override;
+ void readObjectData(Main *bmain, double motionSampleTime) override;
+
+ void read_curve_sample(Curve *cu, double motionSampleTime);
+
+ Mesh *read_mesh(struct Mesh *existing_mesh,
+ double motionSampleTime,
+ int read_flag,
+ float vel_scale,
+ const char **err_str) override;
+
+ protected:
+ pxr::UsdGeomNurbsCurves curve_prim;
+ Curve *m_curve;
+};
+
+#endif /* __USD_READER_NURBS_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_prim.cc b/source/blender/io/usd/intern/usd_reader_prim.cc
new file mode 100644
index 00000000000..bdf96be1d31
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_prim.cc
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_prim.h"
+
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_constraint.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+USDPrimReader::USDPrimReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : m_name(object.GetName().GetString()),
+ m_prim_path(object.GetPrimPath().GetString()),
+ m_prim(object),
+ m_stage(stage),
+ m_import_params(import_params),
+ m_settings(&settings)
+{
+ //@TODO(bjs): This should be handled better
+ if (m_name == "/")
+ m_name = "root";
+}
+
+USDPrimReader::~USDPrimReader()
+{
+}
+
+const pxr::UsdPrim &USDPrimReader::prim() const
+{
+ return m_prim;
+}
+
+Object *USDPrimReader::object() const
+{
+ return m_object;
+}
+
+void USDPrimReader::object(Object *ob)
+{
+ m_object = ob;
+}
+
+bool USDPrimReader::valid() const
+{
+ return m_prim.IsValid();
+}
+
+void USDPrimReader::createObject(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Creating blender object for prim: %s", m_prim.GetPath().GetText());
+ m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_name.c_str());
+ m_object->empty_drawsize = 0.1f;
+ m_object->data = NULL;
+}
+
+void USDPrimReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Reading prim data: %s", m_prim.GetPath().GetText());
+ // m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_prim_path.c_str());
+ // m_object->data = NULL;
+}
+
+void USDPrimReader::addCacheModifier()
+{
+}
+
+int USDPrimReader::refcount() const
+{
+ return m_refcount;
+}
+
+void USDPrimReader::incref()
+{
+ m_refcount++;
+}
+
+void USDPrimReader::decref()
+{
+ m_refcount--;
+ BLI_assert(m_refcount >= 0);
+}
diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h
new file mode 100644
index 00000000000..e44fdc87c52
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_prim.h
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_OBJECT_H__
+#define __USD_READER_OBJECT_H__
+
+#include "usd.h"
+
+#include <pxr/usd/sdf/path.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdShade/material.h>
+#include <pxr/usd/usdUtils/sparseValueWriter.h>
+
+#include <vector>
+
+extern "C" {
+#include "DNA_ID.h"
+}
+
+struct CacheFile;
+struct Main;
+struct Mesh;
+struct Object;
+
+struct ImportSettings {
+ bool do_convert_mat;
+ float conversion_mat[4][4];
+
+ int from_up;
+ int from_forward;
+ float scale;
+ bool is_sequence;
+ bool set_frame_range;
+
+ /* Length and frame offset of file sequences. */
+ int sequence_len;
+ int sequence_offset;
+
+ /* From MeshSeqCacheModifierData.read_flag */
+ int read_flag;
+
+ bool validate_meshes;
+
+ CacheFile *cache_file;
+
+ float vel_scale;
+
+ ImportSettings()
+ : do_convert_mat(false),
+ from_up(0),
+ from_forward(0),
+ scale(1.0f),
+ is_sequence(false),
+ set_frame_range(false),
+ sequence_len(1),
+ sequence_offset(0),
+ read_flag(0),
+ validate_meshes(false),
+ cache_file(NULL),
+ vel_scale(1.0f)
+ {
+ }
+};
+
+// Most generic USD Reader
+
+class USDPrimReader {
+
+ protected:
+ std::string m_name;
+ std::string m_prim_path;
+ Object *m_object;
+ pxr::UsdPrim m_prim;
+ pxr::UsdStageRefPtr m_stage;
+ const USDImportParams &m_import_params;
+ USDPrimReader *m_parent_reader;
+
+ ImportSettings *m_settings;
+
+ int m_refcount;
+
+ public:
+ // USDPrimReader(pxr::UsdPrim* prim, ImportSettings &settings);
+ USDPrimReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings);
+ ~USDPrimReader();
+
+ const pxr::UsdPrim &prim() const;
+
+ virtual bool valid() const;
+
+ virtual void createObject(Main *bmain, double motionSampleTime);
+ virtual void readObjectData(Main *bmain, double motionSampleTime);
+
+ Object *object() const;
+ void object(Object *ob);
+
+ USDPrimReader *parent() const
+ {
+ return m_parent_reader;
+ }
+ void parent(USDPrimReader *parent)
+ {
+ m_parent_reader = parent;
+ }
+
+ int refcount() const;
+ void incref();
+ void decref();
+
+ virtual void addCacheModifier();
+
+ const std::string &name() const
+ {
+ return m_name;
+ }
+ const std::string &prim_path() const
+ {
+ return m_prim_path;
+ }
+};
+
+// template<typename Schema> static bool has_animations(Schema &schema, ImportSettings *settings)
+// {
+// return settings->is_sequence || !schema.isConstant();
+// }
+
+// class USDObjectReader {
+// protected:
+// std::string m_name;
+// std::string m_object_name;
+// std::string m_data_name;
+// Object *m_object;
+// pxr::UsdPrim m_iobject;
+
+// ImportSettings *m_settings;
+
+// chrono_t m_min_time;
+// chrono_t m_max_time;
+
+// /* Use reference counting since the same reader may be used by multiple
+// * modifiers and/or constraints. */
+// int m_refcount;
+
+// bool m_inherits_xform;
+
+// public:
+// USDObjectReader *parent_reader;
+
+// public:
+// explicit USDObjectReader(const pxr::UsdPrim &object, ImportSettings &settings);
+
+// virtual ~USDObjectReader();
+
+// const Alembic::USD::IObject &iobject() const;
+
+// typedef std::vector<USDObjectReader *> ptr_vector;
+
+// /**
+// * Returns the transform of this object. This can be the Alembic object
+// * itself (in case of an Empty) or it can be the parent Alembic object.
+// */
+// virtual Alembic::USDGeom::IXform xform();
+
+// Object *object() const;
+// void object(Object *ob);
+
+// const std::string &name() const
+// {
+// return m_name;
+// }
+// const std::string &object_name() const
+// {
+// return m_object_name;
+// }
+// const std::string &data_name() const
+// {
+// return m_data_name;
+// }
+// bool inherits_xform() const
+// {
+// return m_inherits_xform;
+// }
+
+// virtual bool valid() const = 0;
+// virtual bool accepts_object_type(const Alembic::USDCoreAbstract::ObjectHeader &alembic_header,
+// const Object *const ob,
+// const char **err_str) const = 0;
+
+// virtual void readObjectData(Main *bmain, const Alembic::USD::ISampleSelector &sample_sel) = 0;
+
+// virtual struct Mesh *read_mesh(struct Mesh *mesh,
+// const Alembic::USD::ISampleSelector &sample_sel,
+// int read_flag,
+// const char **err_str);
+// virtual bool topology_changed(Mesh *existing_mesh,
+// const Alembic::USD::ISampleSelector &sample_sel);
+
+// /** Reads the object matrix and sets up an object transform if animated. */
+// void setupObjectTransform(const float time);
+
+// void addCacheModifier();
+
+// chrono_t minTime() const;
+// chrono_t maxTime() const;
+
+// int refcount() const;
+// void incref();
+// void decref();
+
+// void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant);
+
+// protected:
+// void determine_inherits_xform();
+// };
+
+// Imath::M44d get_matrix(const Alembic::USDGeom::IXformSchema &schema, const float time);
+
+#endif /* __USD_READER_OBJECT_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc
new file mode 100644
index 00000000000..07ad27a7897
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_stage.cc
@@ -0,0 +1,153 @@
+/*
+ * 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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ */
+
+#include "usd_reader_stage.h"
+#include "usd_reader_camera.h"
+#include "usd_reader_curve.h"
+#include "usd_reader_mesh.h"
+#include "usd_reader_prim.h"
+#include "usd_reader_xform.h"
+
+#include "usd_util.h"
+
+extern "C" {
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_blender_version.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_world.h"
+
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+#include <iostream>
+
+namespace USD {
+
+USDStageReader::USDStageReader(struct Main *bmain, const char *filename)
+{
+ m_stage = pxr::UsdStage::Open(filename);
+}
+
+USDStageReader::~USDStageReader()
+{
+ clear_readers();
+
+ m_stage->Unload();
+}
+
+bool USDStageReader::valid() const
+{
+ // TODO: Implement
+ return true;
+}
+
+static USDPrimReader *_handlePrim(Main *bmain,
+ pxr::UsdStageRefPtr stage,
+ const USDImportParams &params,
+ pxr::UsdPrim prim,
+ USDPrimReader *parent_reader,
+ std::vector<USDPrimReader *> &readers,
+ ImportSettings &settings)
+{
+ USDPrimReader *reader = NULL;
+
+ reader = USD::create_reader(stage, prim, params, settings);
+
+ if (reader == NULL)
+ return NULL;
+
+ reader->parent(parent_reader);
+ reader->createObject(bmain, 0.0);
+
+ // This check prevents the pseudo 'root' prim to be added
+ if (prim != stage->GetPseudoRoot()) {
+ readers.push_back(reader);
+ reader->incref();
+ }
+
+ for (const auto &childPrim : prim.GetChildren()) {
+ _handlePrim(bmain, stage, params, childPrim, reader, readers, settings);
+ }
+
+ return reader;
+}
+
+std::vector<USDPrimReader *> USDStageReader::collect_readers(Main *bmain,
+ const USDImportParams &params,
+ ImportSettings &settings)
+{
+ m_params = params;
+ m_settings = settings;
+
+ clear_readers();
+
+ // Iterate through stage
+ pxr::UsdPrim root = m_stage->GetPseudoRoot();
+
+ std::string prim_path_mask(params.prim_path_mask);
+
+ if (prim_path_mask.size() > 0) {
+ std::cout << prim_path_mask << '\n';
+ pxr::SdfPath path = pxr::SdfPath(prim_path_mask);
+ pxr::UsdPrim prim = m_stage->GetPrimAtPath(path.StripAllVariantSelections());
+ if (prim.IsValid()) {
+ root = prim;
+ if (path.ContainsPrimVariantSelection()) {
+ // TODO: This will not work properly with setting variants on child prims
+ while (path.ContainsPrimVariantSelection()) {
+ std::pair<std::string, std::string> variantSelection = path.GetVariantSelection();
+ root.GetVariantSet(variantSelection.first).SetVariantSelection(variantSelection.second);
+ path = path.GetParentPath();
+ }
+ }
+ }
+ }
+
+ m_stage->SetInterpolationType(pxr::UsdInterpolationType::UsdInterpolationTypeHeld);
+ _handlePrim(bmain, m_stage, params, root, NULL, m_readers, settings);
+
+ return m_readers;
+}
+
+void USDStageReader::clear_readers()
+{
+ std::vector<USDPrimReader *>::iterator iter;
+ for (iter = m_readers.begin(); iter != m_readers.end(); ++iter) {
+ if (((USDPrimReader *)*iter)->refcount() == 0) {
+ delete *iter;
+ }
+ }
+}
+
+} // Namespace USD \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_stage.h b/source/blender/io/usd/intern/usd_reader_stage.h
new file mode 100644
index 00000000000..d479c04c180
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_stage.h
@@ -0,0 +1,91 @@
+/*
+ * 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) 2016 Kévin Dietrich.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_ARCHIVE_H__
+#define __USD_READER_ARCHIVE_H__
+
+struct Main;
+struct Scene;
+
+#include "usd.h"
+#include "usd_reader_prim.h"
+
+#include <pxr/pxr.h>
+#include <pxr/usd/usd/stage.h>
+
+#include <vector>
+
+struct ImportSettings;
+
+namespace USD {
+
+/* Wrappers around input and output archives. The goal is to be able to use
+ * streams so that unicode paths work on Windows (T49112), and to make sure that
+ * the stream objects remain valid as long as the archives are open.
+ */
+
+class USDStageReader {
+ pxr::UsdStageRefPtr m_stage;
+ USDImportParams m_params;
+ ImportSettings m_settings;
+
+ std::vector<USDPrimReader *> m_readers;
+
+ public:
+ USDStageReader(struct Main *bmain, const char *filename);
+ ~USDStageReader();
+
+ std::vector<USDPrimReader *> collect_readers(struct Main *bmain,
+ const USDImportParams &params,
+ ImportSettings &settings);
+
+ bool valid() const;
+
+ pxr::UsdStageRefPtr stage()
+ {
+ return m_stage;
+ }
+ USDImportParams &params()
+ {
+ return m_params;
+ }
+ ImportSettings &settings()
+ {
+ return m_settings;
+ }
+
+ void params(USDImportParams &a_params)
+ {
+ m_params = a_params;
+ }
+ void settings(ImportSettings &a_settings)
+ {
+ m_settings = a_settings;
+ }
+
+ void clear_readers();
+};
+
+}; // namespace USD
+
+#endif /* __USD_READER_ARCHIVE_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_volume.cc b/source/blender/io/usd/intern/usd_reader_volume.cc
new file mode 100644
index 00000000000..173c94e8b7d
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_volume.cc
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_volume.h"
+
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+#include "DNA_volume_types.h"
+
+#include "BKE_constraint.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_volume.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/pxr.h>
+#include <pxr/usd/usdVol/openVDBAsset.h>
+#include <pxr/usd/usdVol/volume.h>
+
+#include <iostream>
+
+void USDVolumeReader::createObject(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Creating volume for prim: %s", m_prim.GetPath().GetText());
+ Volume *volume = (Volume *)BKE_volume_add(bmain, m_name.c_str());
+ id_us_min(&volume->id);
+
+ m_object = BKE_object_add_only_object(bmain, OB_VOLUME, m_name.c_str());
+ m_object->data = volume;
+}
+
+void USDVolumeReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Reading specific volume data: %s", m_prim.GetPath().GetText());
+
+ m_volume = pxr::UsdVolVolume::Get(m_stage, m_prim.GetPath());
+
+ pxr::UsdVolVolume::FieldMap fields = m_volume.GetFieldPaths();
+
+ std::string filepath;
+
+ Volume *volume = (Volume *)m_object->data;
+ VolumeGrid *defaultGrid = BKE_volume_grid_active_get(volume);
+
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+
+ pxr::UsdPrim fieldPrim = m_stage->GetPrimAtPath(it->second);
+
+ if (fieldPrim.IsA<pxr::UsdVolOpenVDBAsset>()) {
+ pxr::UsdVolOpenVDBAsset fieldBase(fieldPrim);
+
+ pxr::UsdAttribute filepathAttr = fieldBase.GetFilePathAttr();
+ pxr::UsdAttribute fieldNameAttr = fieldBase.GetFieldNameAttr();
+
+ std::string fieldName = "density";
+
+ if (fieldNameAttr.IsAuthored()) {
+ fieldNameAttr.Get(&fieldName, 0.0);
+
+ // A Blender volume creates density by default
+ if (fieldName != "density") {
+ defaultGrid = BKE_volume_grid_add(volume, fieldName.c_str(), VOLUME_GRID_FLOAT);
+ }
+ }
+
+ if (filepathAttr.IsAuthored()) {
+
+ pxr::SdfAssetPath fp;
+ filepathAttr.Get(&fp, 0.0);
+
+ if (filepathAttr.ValueMightBeTimeVarying()) {
+ std::vector<double> filePathTimes;
+ filepathAttr.GetTimeSamples(&filePathTimes);
+
+ int start = (int)filePathTimes.front();
+ int end = (int)filePathTimes.back();
+
+ volume->is_sequence = (char)true;
+ volume->frame_start = start;
+ volume->frame_duration = (end - start) + 1;
+ }
+
+ filepath = fp.GetResolvedPath();
+
+ strcpy(volume->filepath, filepath.c_str());
+ }
+ }
+ }
+
+ USDXformReader::readObjectData(bmain, motionSampleTime);
+}
diff --git a/source/blender/io/usd/intern/usd_reader_volume.h b/source/blender/io/usd/intern/usd_reader_volume.h
new file mode 100644
index 00000000000..773b5f43279
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_volume.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_VOLUME_H__
+#define __USD_READER_VOLUME_H__
+
+#include "usd.h"
+#include "usd_reader_xform.h"
+
+#include "pxr/usd/usdVol/volume.h"
+
+class USDVolumeReader : public USDXformReader {
+
+ public:
+ USDVolumeReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDXformReader(stage, object, import_params, settings)
+ {
+ }
+
+ void createObject(Main *bmain, double motionSampleTime) override;
+ void readObjectData(Main *bmain, double motionSampleTime) override;
+
+ pxr::UsdVolVolume m_volume;
+};
+
+#endif /* __USD_READER_VOLUME_H__ */
diff --git a/source/blender/io/usd/intern/usd_reader_xform.cc b/source/blender/io/usd/intern/usd_reader_xform.cc
new file mode 100644
index 00000000000..fbefa2a50bf
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_xform.cc
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#include "usd_reader_xform.h"
+#include "usd_reader_prim.h"
+
+extern "C" {
+#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX */
+
+#include "BKE_constraint.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_geom.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+}
+
+#include <pxr/base/gf/math.h>
+#include <pxr/pxr.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/xform.h>
+
+void USDXformReader::createObject(Main *bmain, double motionSampleTime)
+{
+ WM_reportf(RPT_WARNING, "Creating blender object for prim: %s", m_prim.GetPath().GetText());
+ m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_name.c_str());
+ m_object->empty_drawsize = 0.1f;
+ m_object->data = NULL;
+}
+
+void USDXformReader::readObjectData(Main *bmain, double motionSampleTime)
+{
+ USDPrimReader::readObjectData(bmain, motionSampleTime);
+
+ WM_reportf(RPT_WARNING, "Reading specific xform data: %s", m_prim.GetPath().GetText());
+
+ bool is_constant;
+ float transform_from_usd[4][4];
+
+ read_matrix(transform_from_usd, motionSampleTime, 1.0f, is_constant);
+
+ if (!is_constant) {
+ bConstraint *con = BKE_constraint_add_for_object(
+ m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
+ bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
+ BLI_strncpy(data->object_path, m_prim.GetPath().GetText(), FILE_MAX);
+
+ data->cache_file = m_settings->cache_file;
+ id_us_plus(&data->cache_file->id);
+ }
+
+ BKE_object_apply_mat4(m_object, transform_from_usd, true, false);
+}
+
+typedef float m4[4];
+
+void USDXformReader::read_matrix(float r_mat[4][4] /* local matrix */,
+ const float time,
+ const float scale,
+ bool &is_constant)
+{
+ is_constant = true;
+ pxr::UsdGeomXformable xformable = pxr::UsdGeomXformable(
+ m_prim); // pxr::UsdGeomXformable::Get(m_stage, m_prim.GetPath());
+
+ bool resetsXformStack = false;
+ std::vector<pxr::UsdGeomXformOp> orderedXformOps = xformable.GetOrderedXformOps(
+ &resetsXformStack);
+
+ unit_m4(r_mat);
+
+ if (orderedXformOps.size() <= 0)
+ return;
+
+ int opCount = 0;
+ for (std::vector<pxr::UsdGeomXformOp>::iterator I = orderedXformOps.begin();
+ I != orderedXformOps.end();
+ ++I) {
+
+ pxr::UsdGeomXformOp &xformOp = (*I);
+
+ is_constant = !xformOp.MightBeTimeVarying();
+
+ pxr::GfMatrix4d mat = xformOp.GetOpTransform(time) * pxr::GfMatrix4d(1.0f).SetScale(scale);
+
+ float t_mat[4][4];
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ t_mat[j][i] = mat[j][i];
+ }
+ }
+ mul_m4_m4m4(r_mat, r_mat, t_mat);
+ opCount++;
+ }
+} \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_reader_xform.h b/source/blender/io/usd/intern/usd_reader_xform.h
new file mode 100644
index 00000000000..7c8bf397c5f
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_reader_xform.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_READER_XFORM_H__
+#define __USD_READER_XFORM_H__
+
+#include "usd.h"
+#include "usd_reader_prim.h"
+
+class USDXformReader : public USDPrimReader {
+
+ public:
+ USDXformReader(pxr::UsdStageRefPtr stage,
+ const pxr::UsdPrim &object,
+ const USDImportParams &import_params,
+ ImportSettings &settings)
+ : USDPrimReader(stage, object, import_params, settings)
+ {
+ }
+
+ void createObject(Main *bmain, double motionSampleTime) override;
+ void readObjectData(Main *bmain, double motionSampleTime) override;
+
+ void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant);
+};
+
+#endif /* __USD_READER_XFORM_H__ */
diff --git a/source/blender/io/usd/intern/usd_util.cc b/source/blender/io/usd/intern/usd_util.cc
new file mode 100644
index 00000000000..1c70fe9cb28
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_util.cc
@@ -0,0 +1,149 @@
+/*
+ * 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 "usd_util.h"
+#include "usd_hierarchy_iterator.h"
+
+#include "usd_reader_camera.h"
+#include "usd_reader_curve.h"
+#include "usd_reader_geom.h"
+#include "usd_reader_light.h"
+#include "usd_reader_mesh.h"
+#include "usd_reader_nurbs.h"
+#include "usd_reader_prim.h"
+#include "usd_reader_stage.h"
+#include "usd_reader_volume.h"
+#include "usd_reader_xform.h"
+
+extern "C" {
+#include "BKE_animsys.h"
+#include "BKE_colorband.h"
+#include "BKE_colortools.h"
+#include "BKE_key.h"
+#include "BKE_node.h"
+
+#include "DNA_color_types.h"
+#include "DNA_light_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "BKE_blender_version.h"
+#include "BKE_cachefile.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_layer.h"
+#include "BKE_light.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_world.h"
+
+#include "BLI_fileops.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+}
+#include "MEM_guardedalloc.h"
+
+#include <algorithm>
+#include <cctype>
+#include <string>
+#include <utility>
+
+#include <pxr/base/tf/stringUtils.h>
+#include <pxr/pxr.h>
+#include <pxr/usd/usdGeom/camera.h>
+#include <pxr/usd/usdGeom/curves.h>
+#include <pxr/usd/usdGeom/mesh.h>
+#include <pxr/usd/usdGeom/nurbsCurves.h>
+#include <pxr/usd/usdGeom/scope.h>
+#include <pxr/usd/usdLux/light.h>
+
+namespace USD {
+
+USDPrimReader *create_reader(const pxr::UsdStageRefPtr &stage,
+ const pxr::UsdPrim &prim,
+ const USDImportParams &params,
+ ImportSettings &settings)
+{
+ USDPrimReader *reader = nullptr;
+
+ if (params.import_cameras && prim.IsA<pxr::UsdGeomCamera>()) {
+ reader = new USDCameraReader(stage, prim, params, settings);
+ }
+ else if (params.import_curves && prim.IsA<pxr::UsdGeomBasisCurves>()) {
+ reader = new USDCurvesReader(stage, prim, params, settings);
+ }
+ else if (params.import_curves && prim.IsA<pxr::UsdGeomNurbsCurves>()) {
+ reader = new USDNurbsReader(stage, prim, params, settings);
+ }
+ else if (params.import_meshes && prim.IsA<pxr::UsdGeomMesh>()) {
+ reader = new USDMeshReader(stage, prim, params, settings);
+ }
+ else if (params.import_lights && prim.IsA<pxr::UsdLuxLight>()) {
+ reader = new USDLightReader(stage, prim, params, settings);
+ }
+ else if (params.import_volumes && prim.IsA<pxr::UsdVolVolume>()) {
+ reader = new USDVolumeReader(stage, prim, params, settings);
+ }
+ else {
+ reader = new USDXformReader(stage, prim, params, settings);
+ }
+
+ return reader;
+}
+
+// TODO: The handle does not have the proper import params or settings
+USDPrimReader *create_fake_reader(USD::USDStageReader *archive, const pxr::UsdPrim &prim)
+{
+ USDPrimReader *reader = nullptr;
+ if (prim.IsA<pxr::UsdGeomCamera>()) {
+ reader = new USDCameraReader(archive->stage(), prim, archive->params(), archive->settings());
+ }
+ else if (prim.IsA<pxr::UsdGeomBasisCurves>()) {
+ reader = new USDCurvesReader(archive->stage(), prim, archive->params(), archive->settings());
+ }
+ else if (prim.IsA<pxr::UsdGeomNurbsCurves>()) {
+ reader = new USDNurbsReader(archive->stage(), prim, archive->params(), archive->settings());
+ }
+ else if (prim.IsA<pxr::UsdGeomMesh>()) {
+ reader = new USDMeshReader(archive->stage(), prim, archive->params(), archive->settings());
+ }
+ else if (prim.IsA<pxr::UsdLuxLight>()) {
+ reader = new USDLightReader(archive->stage(), prim, archive->params(), archive->settings());
+ }
+ else if (prim.IsA<pxr::UsdVolVolume>()) {
+ reader = new USDVolumeReader(archive->stage(), prim, archive->params(), archive->settings());
+ }
+ else {
+ reader = new USDXformReader(archive->stage(), prim, archive->params(), archive->settings());
+ }
+ return reader;
+}
+
+} // Namespace USD \ No newline at end of file
diff --git a/source/blender/io/usd/intern/usd_util.h b/source/blender/io/usd/intern/usd_util.h
new file mode 100644
index 00000000000..7b9da0facc2
--- /dev/null
+++ b/source/blender/io/usd/intern/usd_util.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup busd
+ */
+
+#ifndef __USD_UTIL_H__
+#define __USD_UTIL_H__
+
+#include <string>
+
+#ifdef _MSC_VER
+# define USD_INLINE static __forceinline
+#else
+# define USD_INLINE static inline
+#endif
+
+#include <pxr/pxr.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdLux/light.h>
+#include <pxr/usd/usdShade/material.h>
+
+#include "usd.h"
+#include "usd_exporter_context.h"
+
+class USDPrimReader;
+struct ImportSettings;
+
+struct Light;
+
+struct Material;
+struct bNodeTree;
+
+namespace USD {
+
+USDPrimReader *create_reader(const pxr::UsdStageRefPtr &stage,
+ const pxr::UsdPrim &prim,
+ const USDImportParams &params,
+ ImportSettings &settings);
+USDPrimReader *create_fake_reader(class USDStageReader *archive, const pxr::UsdPrim &prim);
+
+} // Namespace USD
+
+#endif /* __USD_UTIL_H__ */
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 40e2d0d8674..d2d3503c69f 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -26,6 +26,11 @@ extern "C" {
#endif
struct bContext;
+struct Object;
+struct CacheReader;
+struct CacheFile;
+
+typedef struct USDStageHandle USDStageHandle;
struct USDExportParams {
bool export_animation;
@@ -39,6 +44,26 @@ struct USDExportParams {
enum eEvaluationMode evaluation_mode;
};
+struct USDImportParams {
+ float scale;
+ float vel_scale;
+ bool is_sequence;
+ bool set_frame_range;
+ int sequence_len;
+ int offset;
+ bool validate_meshes;
+ char global_read_flag;
+ bool import_cameras;
+ bool import_curves;
+ bool import_lights;
+ bool import_materials;
+ bool import_meshes;
+ bool import_volumes;
+ char *prim_path_mask;
+ bool import_subdiv;
+ bool create_collection;
+};
+
/* The USD_export takes a as_background_job parameter, and returns a boolean.
*
* When as_background_job=true, returns false immediately after scheduling
@@ -53,8 +78,46 @@ bool USD_export(struct bContext *C,
const struct USDExportParams *params,
bool as_background_job);
+bool USD_import(struct bContext *C,
+ const char *filepath,
+ const struct USDImportParams *params,
+ bool as_background_job);
+
int USD_get_version(void);
+// ----- USD Import and Mesh Cache interface
+
+USDStageHandle *USD_create_handle(struct Main *bmain,
+ const char *filename,
+ struct ListBase *object_paths);
+
+void USD_free_handle(USDStageHandle *handle);
+
+void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale);
+
+/* Either modifies current_mesh in-place or constructs a new mesh. */
+struct Mesh *USD_read_mesh(struct CacheReader *reader,
+ struct Object *ob,
+ struct Mesh *current_mesh,
+ const float time,
+ const char **err_str,
+ int flags,
+ float vel_scale);
+
+bool USD_mesh_topology_changed(struct CacheReader *reader,
+ struct Object *ob,
+ struct Mesh *existing_mesh,
+ const float time,
+ const char **err_str);
+
+struct CacheReader *CacheReader_open_usd_object(struct USDStageHandle *handle,
+ struct CacheReader *reader,
+ struct Object *object,
+ const char *object_path);
+
+void USDCacheReader_incref(struct CacheReader *reader);
+void USDCacheReader_free(struct CacheReader *reader);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_cachefile_defaults.h b/source/blender/makesdna/DNA_cachefile_defaults.h
index d37994bb488..521b72567d4 100644
--- a/source/blender/makesdna/DNA_cachefile_defaults.h
+++ b/source/blender/makesdna/DNA_cachefile_defaults.h
@@ -36,6 +36,7 @@
.scale = 1.0f, \
.object_paths ={NULL, NULL}, \
\
+ .type = 0, \
.handle = NULL, \
.handle_filepath[0] = '\0', \
.handle_readers = NULL, \
diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
index 04c99c6c4b1..19c00d0d80a 100644
--- a/source/blender/makesdna/DNA_cachefile_types.h
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -31,6 +31,17 @@ extern "C" {
struct GSet;
+/* CacheFile::type */
+enum {
+ #ifdef WITH_ALEMBIC
+ CACHEFILE_TYPE_ALEMBIC = 1,
+ #endif
+ #ifdef WITH_USD
+ CACHEFILE_TYPE_USD = 2,
+ #endif
+ CACHE_FILE_TYPE_INVALID = 0,
+};
+
/* CacheFile::flag */
enum {
CACHEFILE_DS_EXPAND = (1 << 0),
@@ -46,11 +57,15 @@ enum {
/* Representation of an object's path inside the Alembic file.
* Note that this is not a file path. */
-typedef struct AlembicObjectPath {
- struct AlembicObjectPath *next, *prev;
+typedef struct CacheObjectPath {
+ struct CacheObjectPath *next, *prev;
char path[4096];
-} AlembicObjectPath;
+} CacheObjectPath;
+
+typedef struct CacheArchiveHandle {
+ int unused;
+} CacheArchiveHandle;
/* CacheFile::velocity_unit
* Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */
@@ -83,15 +98,17 @@ typedef struct CacheFile {
/** Animation flag. */
short flag;
short draw_flag; /* UNUSED */
+
+ char type;
- char _pad[3];
+ char _pad[2];
char velocity_unit;
/* Name of the velocity property in the Alembic file. */
char velocity_name[64];
/* Runtime */
- struct AbcArchiveHandle *handle;
+ struct CacheArchiveHandle *handle;
char handle_filepath[1024];
struct GSet *handle_readers;
} CacheFile;
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index e3b5ecfac04..ea585a59b53 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -75,7 +75,7 @@ typedef struct CustomData {
* MUST be >= CD_NUMTYPES, but we cant use a define here.
* Correct size is ensured in CustomData_update_typemap assert().
*/
- int typemap[51];
+ int typemap[56];
/** Number of layers, size of layers array. */
int totlayer, maxlayer;
/** In editmode, total size of all data layers. */
@@ -156,8 +156,15 @@ typedef enum CustomDataType {
CD_PROP_FLOAT2 = 49,
CD_PROP_BOOL = 50,
+
+ CD_VALUE_FLOAT = 51,
+ CD_VALUE_INT = 52,
+ CD_VALUE_F3 = 53,
+ CD_VALUE_I3 = 54,
- CD_NUMTYPES = 51,
+ CD_VELOCITY = 55,
+
+ CD_NUMTYPES = 56,
} CustomDataType;
/* Bits for CustomDataMask */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 03cf4aca963..edbfbbbf03d 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -2116,6 +2116,8 @@ typedef struct MeshSeqCacheModifierData {
/** 1024 = FILE_MAX. */
char object_path[1024];
+ float vel_fac;
+
char read_flag;
char _pad[3];
@@ -2155,7 +2157,11 @@ enum {
* the mesh topology changes, but this heuristic sometimes fails. In these cases, users can
* disable interpolation with this flag. */
MOD_MESHSEQ_INTERPOLATE_VERTICES = (1 << 4),
+ MOD_MESHSEQ_READ_ATTR = (1 << 5),
+ MOD_MESHSEQ_READ_VELS = (1 << 6),
};
+// USD Import re-added attr and vel. We are unsure as to why they were removed
+// They are necessary for full USD Import of data
typedef struct SDefBind {
unsigned int *vert_inds;
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
index c25cea1b4b3..b93f494072c 100644
--- a/source/blender/makesrna/intern/rna_cachefile.c
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -64,8 +64,8 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P
/* cachefile.object_paths */
static void rna_def_alembic_object_path(BlenderRNA *brna)
{
- StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPath", NULL);
- RNA_def_struct_sdna(srna, "AlembicObjectPath");
+ StructRNA *srna = RNA_def_struct(brna, "CacheObjectPath", NULL);
+ RNA_def_struct_sdna(srna, "CacheObjectPath");
RNA_def_struct_ui_text(srna, "Object Path", "Path of an object inside of an Alembic archive");
RNA_def_struct_ui_icon(srna, ICON_NONE);
@@ -81,8 +81,8 @@ static void rna_def_alembic_object_path(BlenderRNA *brna)
/* cachefile.object_paths */
static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
{
- RNA_def_property_srna(cprop, "AlembicObjectPaths");
- StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPaths", NULL);
+ RNA_def_property_srna(cprop, "CacheObjectPaths");
+ StructRNA *srna = RNA_def_struct(brna, "CacheObjectPaths", NULL);
RNA_def_struct_sdna(srna, "CacheFile");
RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths");
}
@@ -169,8 +169,8 @@ static void rna_def_cachefile(BlenderRNA *brna)
NULL,
NULL,
NULL);
- RNA_def_property_struct_type(prop, "AlembicObjectPath");
- RNA_def_property_srna(prop, "AlembicObjectPaths");
+ RNA_def_property_struct_type(prop, "CacheObjectPath");
+ RNA_def_property_srna(prop, "CacheObjectPaths");
RNA_def_property_ui_text(
prop, "Object Paths", "Paths of the objects inside the Alembic archive");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 88953e8fddf..8a4c707e39c 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -6135,8 +6135,12 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
{MOD_MESHSEQ_READ_POLY, "POLY", 0, "Faces", ""},
{MOD_MESHSEQ_READ_UV, "UV", 0, "UV", ""},
{MOD_MESHSEQ_READ_COLOR, "COLOR", 0, "Color", ""},
+ {MOD_MESHSEQ_READ_ATTR, "ATTR", 0, "Attributes", ""},
+ {MOD_MESHSEQ_READ_VELS, "VELS", 0, "Velocities", ""},
{0, NULL, 0, NULL, NULL},
};
+ // USD Import re-added these. We are unsure as to why they were removed
+ // They are necessary for full USD Import of data
prop = RNA_def_property(srna, "read_data", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 3a7addcba94..6300bc73a15 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -139,6 +139,16 @@ if(WITH_ALEMBIC)
)
endif()
+if(WITH_USD)
+ add_definitions(-DWITH_USD)
+ list(APPEND INC
+ ../io/usd
+ )
+ list(APPEND LIB
+ bf_usd
+ )
+endif()
+
if(WITH_MOD_REMESH)
list(APPEND INC
../../../intern/dualcon
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 2c01857adb1..a2d65c49506 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -38,6 +38,7 @@
#include "BKE_cachefile.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_lib_query.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -49,24 +50,39 @@
#include "BLO_read_write.h"
+#include "BLI_string.h"
+
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
+#include "MEM_guardedalloc.h"
+
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
# include "BKE_global.h"
# include "BKE_lib_id.h"
#endif
+#ifdef WITH_USD
+# include "BKE_global.h"
+# include "BKE_library.h"
+# include "usd.h"
+#endif
+
static void initData(ModifierData *md)
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mcmd, modifier));
+ mcmd->cache_file = NULL;
+ mcmd->object_path[0] = '\0';
+ mcmd->vel_fac = 1.0f;
+ mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
+
MEMCPY_STRUCT_AFTER(mcmd, DNA_struct_default_get(MeshSeqCacheModifierData), modifier);
}
@@ -109,7 +125,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
-#ifdef WITH_ALEMBIC
+#if defined(WITH_USD) || defined(WITH_ALEMBIC)
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
/* Only used to check whether we are operating on org data or not... */
@@ -121,7 +137,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const float frame = DEG_get_ctime(ctx->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
const char *err_str = NULL;
+ switch (cache_file->type) {
+# ifdef WITH_ALEMBIC
+ case CACHEFILE_TYPE_ALEMBIC:
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path);
@@ -178,7 +197,67 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
mesh = org_mesh;
}
- return result ? result : mesh;
+ if (!result) {
+ result = mesh;
+ }
+ return result;
+ break;
+# endif
+# ifdef WITH_USD
+ case CACHEFILE_TYPE_USD:
+ if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
+ STRNCPY(mcmd->reader_object_path, mcmd->object_path);
+ BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path);
+ if (!mcmd->reader) {
+ printf("Could not create usd reader\n");
+ modifier_setError(md, "Could not create USD reader for file %s", cache_file->filepath);
+ return mesh;
+ }
+ }
+
+ /* If this invocation is for the ORCO mesh, and the mesh in Alembic hasn't changed topology,
+ * we must return the mesh as-is instead of deforming it. */
+ if (ctx->flag & MOD_APPLY_ORCO &&
+ !USD_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time * FPS, &err_str)) {
+ printf("ORCO and no topology changed\n");
+ return mesh;
+ }
+
+ if (me != NULL) {
+ MVert *mvert = mesh->mvert;
+ MEdge *medge = mesh->medge;
+ MPoly *mpoly = mesh->mpoly;
+
+ /* TODO(sybren+bastien): possibly check relevant custom data layers (UV/color depending on
+ * flags) and duplicate those too. */
+ if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
+ /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
+ BKE_id_copy_ex(NULL,
+ &mesh->id,
+ (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW);
+ }
+ }
+
+ Mesh *usd_result = USD_read_mesh(
+ mcmd->reader, ctx->object, mesh, time * FPS, &err_str, mcmd->read_flag, mcmd->vel_fac);
+ if (err_str) {
+ modifier_setError(md, "%s", err_str);
+ }
+
+ if (!ELEM(usd_result, NULL, mesh) && (mesh != org_mesh)) {
+ BKE_id_free(NULL, mesh);
+ mesh = org_mesh;
+ }
+
+ return usd_result ? usd_result : mesh;
+ break;
+# endif
+ default:
+ return NULL;
+ break;
+ }
#else
UNUSED_VARS(ctx, md);
return mesh;
@@ -187,7 +266,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
static bool dependsOnTime(ModifierData *md)
{
-#ifdef WITH_ALEMBIC
+#if defined(WITH_USD) || defined(WITH_ALEMBIC)
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
return (mcmd->cache_file != NULL);
#else